github.com/diadata-org/diadata@v1.4.593/pkg/utils/dates.go (about)

     1  package utils
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"time"
     7  )
     8  
     9  // StrToUnixtime converts a string corresponding to an int to Unix time
    10  func StrToUnixtime(s string) (t time.Time, err error) {
    11  	i, err := strconv.ParseInt(s, 10, 64)
    12  	if err != nil {
    13  		return
    14  	}
    15  	t = time.Unix(i, 0)
    16  	return
    17  }
    18  
    19  // CheckWeekDay returns true if @date is not weekend and false otherwise.
    20  func CheckWeekDay(date time.Time) bool {
    21  	if date.Weekday() == time.Saturday || date.Weekday() == time.Sunday {
    22  		return false
    23  	}
    24  	return true
    25  }
    26  
    27  // ContainsDay returns true if day @date is contained in slice @s, independent of the daytime.
    28  // As a consequence, be cautious when comparing days in different timezones.
    29  func ContainsDay(s []time.Time, date time.Time) bool {
    30  	for _, a := range s {
    31  		if SameDays(a, date) {
    32  			return true
    33  		}
    34  	}
    35  	return false
    36  }
    37  
    38  // SameDays returns true if @date1 is the same date as @date2, independent of the daytime.
    39  func SameDays(date1, date2 time.Time) bool {
    40  	if date1.Year() == date2.Year() && date1.Month() == date2.Month() && date1.Day() == date2.Day() {
    41  		return true
    42  	}
    43  	return false
    44  }
    45  
    46  // AfterDay returns true if date1 is a date after date2, irrespective of the daytime.
    47  // The go method "After" respects daytime.
    48  func AfterDay(date1, date2 time.Time) bool {
    49  	date1Str := date1.Format("2006-01-02")
    50  	date2Str := date2.Format("2006-01-02")
    51  	return date1Str > date2Str
    52  }
    53  
    54  // CountDays returns the number of days between
    55  // @dateInit and @dateFinal, both given as converted from a string in the format yyyy-mm-dd, excluding the last day.
    56  // @bool If true only business days are counted.
    57  func CountDays(dateInit, dateFinal time.Time, business bool) (days int, err error) {
    58  
    59  	if SameDays(dateInit, dateFinal) {
    60  		return 0, nil
    61  	}
    62  	days = 0
    63  	if dateInit.After(dateFinal) {
    64  		log.Error("The final date cannot be smaller than the initial date.")
    65  		err = errors.New("date error")
    66  		return
    67  	}
    68  
    69  	for {
    70  		if SameDays(dateInit, dateFinal) {
    71  			return days, nil
    72  		}
    73  		if business {
    74  			if CheckWeekDay(dateInit) {
    75  				days++
    76  			}
    77  			dateInit = dateInit.Add(time.Hour * 24)
    78  		} else {
    79  			days++
    80  			dateInit = dateInit.Add(time.Hour * 24)
    81  		}
    82  	}
    83  }
    84  
    85  // GetHolidays returns "holidays" as non-weekend complement of given days @workdays
    86  func GetHolidays(workdays []time.Time, dateInit, dateFinal time.Time) []time.Time {
    87  
    88  	if AfterDay(dateInit, dateFinal) {
    89  		log.Error("The initial date must not be after the final date.")
    90  		return []time.Time{}
    91  	}
    92  	auxDate := dateInit
    93  	holidays := []time.Time{}
    94  	for !SameDays(auxDate, dateFinal.AddDate(0, 0, 1)) {
    95  		if CheckWeekDay(auxDate) && !ContainsDay(workdays, auxDate) {
    96  			holidays = append(holidays, auxDate)
    97  			auxDate = auxDate.AddDate(0, 0, 1)
    98  		} else {
    99  			auxDate = auxDate.AddDate(0, 0, 1)
   100  		}
   101  	}
   102  	return holidays
   103  }
   104  
   105  // GetYesterday returns the day before @date in the world of strings, formatted as @layout
   106  func GetYesterday(date, layout string) string {
   107  	dateTime, err := time.Parse(layout, date)
   108  	if err != nil {
   109  		log.Printf("Error: %v on date format %s\n", err, date)
   110  	}
   111  	yesterday := dateTime.AddDate(0, 0, -1)
   112  	return yesterday.Format(layout)
   113  }
   114  
   115  // GetTomorrow returns the day before @date in the world of strings, formatted as @layout
   116  func GetTomorrow(date, layout string) string {
   117  	dateTime, err := time.Parse(layout, date)
   118  	if err != nil {
   119  		log.Printf("Error: %v on date format %s\n", err, date)
   120  	}
   121  	tomorrow := dateTime.AddDate(0, 0, 1)
   122  	return tomorrow.Format(layout)
   123  }
   124  
   125  // MakeTimeRanges returns @numRanges start- and endtimes partitioning [@timeInit, @timeFinal] in intervals of identical size.
   126  func MakeTimeRanges(timeInit, timeFinal time.Time, numRanges int) (starttimes, endtimes []time.Time) {
   127  	a := timeInit
   128  	b := timeFinal
   129  	totalSize := b.Sub(a)
   130  	sizeRange := totalSize / time.Duration(numRanges)
   131  	starttime := timeInit
   132  	for k := 0; k < numRanges; k++ {
   133  		starttimes = append(starttimes, starttime)
   134  		endtimes = append(endtimes, starttime.Add(sizeRange))
   135  		starttime = starttime.Add(sizeRange)
   136  	}
   137  	return
   138  }
   139  
   140  // MakeTimerange parses Unix timestamps given as strings.
   141  // In case one of the two is empty, it returns a time-range based on @timeRange.
   142  // Default is a 24h window ending now.
   143  func MakeTimerange(starttimeString string, endtimeString string, timeRange time.Duration) (starttime time.Time, endtime time.Time, err error) {
   144  
   145  	var (
   146  		starttimeInt int64
   147  		endtimeInt   int64
   148  	)
   149  
   150  	if starttimeString == "" && endtimeString == "" {
   151  		endtime = time.Now()
   152  		starttime = endtime.Add(-timeRange)
   153  	} else if starttimeString == "" && endtimeString != "" {
   154  		// zero time if not given
   155  		endtimeInt, err = strconv.ParseInt(endtimeString, 10, 64)
   156  		if err != nil {
   157  			return
   158  		}
   159  		endtime = time.Unix(endtimeInt, 0)
   160  		starttime = endtime.Add(-timeRange)
   161  	} else if starttimeString != "" && endtimeString == "" {
   162  		starttimeInt, err = strconv.ParseInt(starttimeString, 10, 64)
   163  		if err != nil {
   164  			return
   165  		}
   166  		starttime = time.Unix(starttimeInt, 0)
   167  		endtime = starttime.Add(timeRange)
   168  	} else {
   169  		starttimeInt, err = strconv.ParseInt(starttimeString, 10, 64)
   170  		if err != nil {
   171  			return
   172  		}
   173  		starttime = time.Unix(starttimeInt, 0)
   174  		endtimeInt, err = strconv.ParseInt(endtimeString, 10, 64)
   175  		if err != nil {
   176  			return
   177  		}
   178  		endtime = time.Unix(endtimeInt, 0)
   179  	}
   180  	return starttime, endtime, nil
   181  }
   182  
   183  // ValidTimeRange returns true if the interval [@starttime, @endtime] is at most @maxDuration.
   184  func ValidTimeRange(starttime time.Time, endtime time.Time, maxDuration time.Duration) (ok bool) {
   185  	if endtime.Sub(starttime) <= maxDuration {
   186  		ok = true
   187  	}
   188  	return
   189  }