github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xtime/xtime.go (about) 1 package xtime 2 3 import ( 4 "errors" 5 "fmt" 6 "regexp" 7 "strconv" 8 "time" 9 ) 10 11 // === 12 // set 13 // === 14 15 // SetYear sets the year value to given time and returns a new time.Time. 16 func SetYear(t time.Time, year int) time.Time { 17 return time.Date(year, t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location()) 18 } 19 20 // SetMonth sets the month value to given time and returns a new time.Time. 21 func SetMonth(t time.Time, month int) time.Time { 22 return time.Date(t.Year(), time.Month(month), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location()) 23 } 24 25 // SetDay sets the dat value to given time and returns a new time.Time. 26 func SetDay(t time.Time, day int) time.Time { 27 return time.Date(t.Year(), t.Month(), day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location()) 28 } 29 30 // SetHour sets the hour value to given time and returns a new time.Time. 31 func SetHour(t time.Time, hour int) time.Time { 32 return time.Date(t.Year(), t.Month(), t.Day(), hour, t.Minute(), t.Second(), t.Nanosecond(), t.Location()) 33 } 34 35 // SetMinute sets the minute value to given time and returns a new time.Time. 36 func SetMinute(t time.Time, minute int) time.Time { 37 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), minute, t.Second(), t.Nanosecond(), t.Location()) 38 } 39 40 // SetSecond sets the second value to given time and returns a new time.Time. 41 func SetSecond(t time.Time, second int) time.Time { 42 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), second, t.Nanosecond(), t.Location()) 43 } 44 45 // SetMillisecond sets the millisecond value to given time and returns a new time.Time. 46 func SetMillisecond(t time.Time, millisecond int) time.Time { 47 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), millisecond*1e6, t.Location()) 48 } 49 50 // SetMicrosecond sets the microsecond value to given time and returns a new time.Time. 51 func SetMicrosecond(t time.Time, microsecond int) time.Time { 52 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), microsecond*1e3, t.Location()) 53 } 54 55 // SetNanosecond sets the nanosecond value to given time and returns a new time.Time. 56 func SetNanosecond(t time.Time, nanosecond int) time.Time { 57 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), nanosecond, t.Location()) 58 } 59 60 // SetLocation sets the location value to given time and returns a new time.Time. 61 func SetLocation(t time.Time, loc *time.Location) time.Time { 62 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), loc) 63 } 64 65 // == 66 // to 67 // == 68 69 // ToDate returns a new time.Time with the old year, month, day value and parsed location (see GetTimeLocation). 70 func ToDate(t time.Time) time.Time { 71 return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, GetTimeLocation(t)) 72 } 73 74 // ToDateTime returns a new time.Time with the old year, month, day, hour, minute, second value and parsed location (see GetTimeLocation). 75 func ToDateTime(t time.Time) time.Time { 76 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, GetTimeLocation(t)) 77 } 78 79 // ToDateTimeNS returns a new time.Time with the old year, month, day, hour, minute, second, nanosecond value and parsed location (see GetTimeLocation). 80 func ToDateTimeNS(t time.Time) time.Time { 81 return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), GetTimeLocation(t)) 82 } 83 84 // =================== 85 // location & timezone 86 // =================== 87 88 // LocationDuration returns a time.Duration that equals to the duration for given time.Location. 89 func LocationDuration(loc *time.Location) time.Duration { 90 t := time.Date(2020, time.Month(10), 1, 0, 0, 0, 0, loc) 91 tUtc := t.In(time.UTC) 92 t2 := time.Date(tUtc.Year(), tUtc.Month(), tUtc.Day(), tUtc.Hour(), tUtc.Minute(), tUtc.Second(), tUtc.Nanosecond(), loc) 93 return t.Sub(t2) 94 } 95 96 // GetTimeLocation returns a time.Location with empty name for given time.Time. Note that 97 // time.Time.Location() will return an unusable location (UTC or Local or empty name). 98 func GetTimeLocation(t time.Time) *time.Location { 99 du := LocationDuration(t.Location()) 100 return time.FixedZone("", int(du.Seconds())) // use empty name 101 } 102 103 // GetLocalLocation returns a time.Location with empty name for representing time.Local. 104 func GetLocalLocation() *time.Location { 105 du := LocationDuration(time.Local) 106 return time.FixedZone("", int(du.Seconds())) // Local name -> empty 107 } 108 109 // timezoneRegexp represents a UTC offset timezone format, such as `+0:0`, `-01`, `+08:00`, `-12:30`. 110 // For more details of time.RFC3339 offset, see https://tools.ietf.org/html/rfc3339#section-4.2. 111 var timezoneRegexp = regexp.MustCompile(`^([+-])([0-9]{1,2})(?::([0-9]{1,2}))?$`) 112 113 var errWrongFormat = errors.New("xtime: wrong format timezone string") 114 115 // ParseTimezone parses a UTC offset timezone string to time.Location (with UTC+00:00 name), format: `[+-][0-9]{1,2}(:[0-9]{1,2})?`. 116 func ParseTimezone(timezone string) (*time.Location, error) { 117 matches := timezoneRegexp.FindAllStringSubmatch(timezone, 1) 118 if len(matches) == 0 || len(matches[0][1:]) < 3 { 119 return nil, errWrongFormat 120 } 121 122 group := matches[0][1:] 123 signStr, hourStr, minuteStr := group[0], group[1], group[2] 124 sign := +1 125 if signStr == "-" { 126 sign = -1 127 } 128 if minuteStr == "" { 129 minuteStr = "0" 130 } 131 hour, _ := strconv.Atoi(hourStr) // no error 132 minute, _ := strconv.Atoi(minuteStr) // no error 133 134 name := fmt.Sprintf("UTC%s%02d:%02d", signStr, hour, minute) // UTC+00:00 135 offset := sign * (hour*3600 + minute*60) 136 return time.FixedZone(name, offset), nil 137 } 138 139 // TruncateTime returns the result of rounding t down to a multiple of duration (since the zero time). Note that if given time.Time is not in 140 // time.UTC, time.Time.Truncate method will return a wrong result, so in this case please use xtime.TruncateTime. 141 func TruncateTime(t time.Time, du time.Duration) time.Time { 142 if t.Location() == time.UTC { 143 return t.Truncate(du) 144 } 145 utcTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC) 146 r := utcTime.Truncate(du) 147 return time.Date(r.Year(), r.Month(), r.Day(), r.Hour(), r.Minute(), r.Second(), r.Nanosecond(), t.Location()) 148 } 149 150 // ======== 151 // duration 152 // ======== 153 154 // DurationNanosecondComponent returns the nanosecond component of the time.Duration. 155 func DurationNanosecondComponent(d time.Duration) int { 156 ns := d 157 us := d / time.Microsecond 158 return int(ns - us*1e3) // (d / 1e3) * 1e3 159 } 160 161 // DurationMicrosecondComponent returns the microsecond component of the time.Duration. 162 func DurationMicrosecondComponent(d time.Duration) int { 163 us := d / time.Microsecond 164 ms := d / time.Millisecond 165 return int(us - ms*1e3) 166 } 167 168 // DurationMillisecondComponent returns the millisecond component of the time.Duration. 169 func DurationMillisecondComponent(d time.Duration) int { 170 ms := d / time.Millisecond 171 sec := d / time.Second 172 return int(ms - sec*1e3) 173 } 174 175 // DurationSecondComponent returns the second component of the time.Duration. 176 func DurationSecondComponent(d time.Duration) int { 177 sec := d / time.Second 178 min := d / time.Minute 179 return int(sec - min*60) 180 } 181 182 // DurationMinuteComponent returns the minute component of the time.Duration. 183 func DurationMinuteComponent(d time.Duration) int { 184 min := d / time.Minute 185 hour := d / time.Hour 186 return int(min - hour*60) 187 } 188 189 // DurationHourComponent returns the hour component of the time.Duration. 190 func DurationHourComponent(d time.Duration) int { 191 hour := d / time.Hour 192 day := d / (time.Hour * 24) 193 return int(hour - day*24) 194 } 195 196 // DurationDayComponent returns the day component of the time.Duration. 197 func DurationDayComponent(d time.Duration) int { 198 return int(d / (time.Hour * 24)) // total days 199 } 200 201 // DurationTotalNanoseconds returns the value of the time.Duration expressed in whole and fractional nanoseconds. 202 func DurationTotalNanoseconds(d time.Duration) int64 { 203 return int64(d) 204 } 205 206 // DurationTotalMicroseconds returns the value of the time.Duration expressed in whole and fractional microseconds. 207 func DurationTotalMicroseconds(d time.Duration) int64 { 208 return int64(d) / 1e3 // only return int64 209 } 210 211 // DurationTotalMilliseconds returns the value of the time.Duration expressed in whole and fractional milliseconds. 212 func DurationTotalMilliseconds(d time.Duration) int64 { 213 return int64(d) / 1e6 // only return int64 214 } 215 216 // DurationTotalSeconds returns the value of the time.Duration expressed in whole and fractional seconds. 217 func DurationTotalSeconds(d time.Duration) float64 { 218 sec := d / time.Second 219 nsec := d % time.Second 220 return float64(sec) + float64(nsec)/1e9 // a truncation to integer would make them not useful 221 } 222 223 // DurationTotalMinutes returns the value of the time.Duration expressed in whole and fractional minutes. 224 func DurationTotalMinutes(d time.Duration) float64 { 225 min := d / time.Minute 226 nsec := d % time.Minute 227 return float64(min) + float64(nsec)/(60*1e9) 228 } 229 230 // DurationTotalHours returns the value of the time.Duration expressed in whole and fractional hours. 231 func DurationTotalHours(d time.Duration) float64 { 232 hour := d / time.Hour 233 nsec := d % time.Hour 234 return float64(hour) + float64(nsec)/(60*60*1e9) 235 } 236 237 // DurationTotalDays returns the value of the time.Duration expressed in whole and fractional days. 238 func DurationTotalDays(d time.Duration) float64 { 239 day := d / (time.Hour * 24) 240 nsec := d % (time.Hour * 24) 241 return float64(day) + float64(nsec)/(24*60*60*1e9) 242 } 243 244 // ===== 245 // clock 246 // ===== 247 248 // Clock represents an interface used to determine the current time. 249 type Clock interface { 250 Now() time.Time 251 } 252 253 // clockFn is an unexported type that implements Clock interface, see UTC and Local. 254 type clockFn func() time.Time 255 256 // Now implements the Clock interface. 257 func (c clockFn) Now() time.Time { 258 return c() 259 } 260 261 var _ Clock = (*clockFn)(nil) 262 263 var ( 264 // UTC is a function that satisfies the Clock interface, which returns the current time in UTC timezone. 265 UTC Clock = clockFn(func() time.Time { return time.Now().UTC() }) 266 267 // Local is a function that satisfies the Clock interface, which returns the current time in local timezone. 268 Local Clock = clockFn(time.Now) 269 ) 270 271 // CustomClock returns a custom Clock with given time.Time pointer. 272 func CustomClock(t *time.Time) Clock { 273 return clockFn(func() time.Time { return *t }) 274 }