github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/datetime/diff.go (about)

     1  package datetime
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/MontFerret/ferret/pkg/runtime/core"
     7  	"github.com/MontFerret/ferret/pkg/runtime/values"
     8  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
     9  )
    10  
    11  // DATE_DIFF returns the difference between two dates in given time unit.
    12  // @param {DateTime} date1 - First date.
    13  // @param {DateTime} date2 - Second date.
    14  // @param {String} unit - Time unit to return the difference in.
    15  // @param {Boolean} [asFloat=False] - If true amount of unit will be as float.
    16  // @return {Int | Float} - Difference between date1 and date2.
    17  func DateDiff(_ context.Context, args ...core.Value) (core.Value, error) {
    18  	err := core.ValidateArgs(args, 3, 4)
    19  	if err != nil {
    20  		return values.None, err
    21  	}
    22  
    23  	err = core.ValidateValueTypePairs(
    24  		core.NewPairValueType(args[0], types.DateTime),
    25  		core.NewPairValueType(args[1], types.DateTime),
    26  		core.NewPairValueType(args[2], types.String),
    27  	)
    28  	if err != nil {
    29  		return values.None, err
    30  	}
    31  
    32  	date1 := args[0].(values.DateTime)
    33  	date2 := args[1].(values.DateTime)
    34  	unit := args[2].(values.String)
    35  	isFloat := values.NewBoolean(false)
    36  
    37  	if len(args) == 4 {
    38  		err = core.ValidateType(args[3], types.Boolean)
    39  		if err != nil {
    40  			return values.None, err
    41  		}
    42  		isFloat = args[3].(values.Boolean)
    43  	}
    44  
    45  	if date1.Equal(date2.Time) {
    46  		if isFloat {
    47  			return values.NewFloat(0), nil
    48  		}
    49  		return values.NewInt(0), nil
    50  	}
    51  
    52  	var nsecDiff int64
    53  
    54  	if date1.After(date2.Time) {
    55  		nsecDiff = date1.Time.Sub(date2.Time).Nanoseconds()
    56  	} else {
    57  		nsecDiff = date2.Time.Sub(date1.Time).Nanoseconds()
    58  	}
    59  
    60  	unitDiff, err := nsecToUnit(float64(nsecDiff), unit.String())
    61  	if err != nil {
    62  		return values.None, err
    63  	}
    64  
    65  	if !isFloat {
    66  		return values.NewInt(int(unitDiff)), nil
    67  	}
    68  
    69  	return values.NewFloat(unitDiff), nil
    70  }
    71  
    72  func nsecToUnit(nsec float64, unit string) (float64, error) {
    73  	u, err := UnitFromString(unit)
    74  	if err != nil {
    75  		return -1, err
    76  	}
    77  	return nsec / u.Nanosecond(), nil
    78  }