bitbucket.org/ai69/amoy@v0.2.3/date.go (about) 1 package amoy 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 ) 8 9 var ( 10 // ZeroDate is the default Date with zero values. 11 ZeroDate = Date{} 12 13 // MinDate is the minimum Date value supported. 14 MinDate = Date{1, 1, 1} 15 16 // MaxDate is the maximum Date value supported. 17 MaxDate = Date{9999, 12, 31} 18 ) 19 20 // Date represents the missing data structure for date. 21 type Date struct { 22 year int 23 month int 24 day int 25 } 26 27 func (d Date) String() string { 28 return fmt.Sprintf(`%04d-%02d-%02d`, d.year, d.month, d.day) 29 } 30 31 // Year returns the year in which d occurs. 32 func (d Date) Year() int { 33 return d.year 34 } 35 36 // Month returns the month of the year specified by d. 37 func (d Date) Month() time.Month { 38 return time.Month(d.month) 39 } 40 41 // Day returns the day of the month specified by d. 42 func (d Date) Day() int { 43 return d.day 44 } 45 46 // Sub returns the duration between two dates. 47 func (d Date) Sub(t Date) time.Duration { 48 return d.LocalTime().Sub(t.LocalTime()) 49 } 50 51 // SubInDay returns the duration between two dates in day. 52 func (d Date) SubInDay(t Date) int { 53 return int(d.Sub(t).Hours() / 24) 54 } 55 56 // Add returns a Date instance for the duration after the given date. 57 func (d Date) Add(t time.Duration) Date { 58 return NewDateFromTime(d.UTCTime().Add(t)) 59 } 60 61 // AddDay returns a Date instance for given days after the current date. 62 func (d Date) AddDay(n int) Date { 63 return NewDateFromTime(d.UTCTime().Add(Days(float64(n)))) 64 } 65 66 // AddMonth returns a Date instance for given months after the current date. 67 func (d Date) AddMonth(n int) Date { 68 t := NewUTCDay(d.year, time.Month(d.month+n), d.day) 69 return NewDateFromTime(t) 70 } 71 72 // AddYear returns a Date instance for given years after the current date. 73 func (d Date) AddYear(n int) Date { 74 t := NewUTCDay(d.year+n, time.Month(d.month), d.day) 75 return NewDateFromTime(t) 76 } 77 78 // After indicates if current date is later than the given date. 79 func (d Date) After(t Date) bool { 80 if d.year != t.year { 81 return d.year > t.year 82 } else if d.month != t.month { 83 return d.month > t.month 84 } else { 85 return d.day > t.day 86 } 87 } 88 89 // Before indicates if current date is earlier than the given date. 90 func (d Date) Before(t Date) bool { 91 if d.year != t.year { 92 return d.year < t.year 93 } else if d.month != t.month { 94 return d.month < t.month 95 } else { 96 return d.day < t.day 97 } 98 } 99 100 // Equal indicates if current date and the given date are equal. 101 func (d Date) Equal(t Date) bool { 102 return d.IsSameDay(t) 103 } 104 105 // IsZero indicates if current date is zero value. 106 func (d Date) IsZero() bool { 107 return d.Equal(ZeroDate) 108 } 109 110 // IsSameYear returns true if current date and the given date are in the same year. 111 func (d Date) IsSameYear(t Date) bool { 112 return d.year == t.year 113 } 114 115 // IsSameMonth returns true if current date and the given date are in the same month of the same year. 116 func (d Date) IsSameMonth(t Date) bool { 117 return d.year == t.year && d.month == t.month 118 } 119 120 // IsSameDay returns true if current date and the given date are in the same day of the same month of the same year. 121 func (d Date) IsSameDay(t Date) bool { 122 return d.year == t.year && d.month == t.month && d.day == t.day 123 } 124 125 // Time returns a time.Time with given location for current instance. 126 func (d Date) Time(loc *time.Location) time.Time { 127 return time.Date(d.year, time.Month(d.month), d.day, 0, 0, 0, 0, loc) 128 } 129 130 // LocalTime returns a local time.Time for current instance. 131 func (d Date) LocalTime() time.Time { 132 return d.Time(time.Local) 133 } 134 135 // UTCTime returns a UTC time.Time for current instance. 136 func (d Date) UTCTime() time.Time { 137 return d.Time(time.UTC) 138 } 139 140 // Clone returns a copy of current instance. 141 func (d *Date) Clone() Date { 142 return Date{ 143 d.year, 144 d.month, 145 d.day, 146 } 147 } 148 149 // NewDateFromTime converts a time.Time into Date instance. 150 func NewDateFromTime(t time.Time) Date { 151 return Date{ 152 t.Year(), 153 int(t.Month()), 154 t.Day(), 155 } 156 } 157 158 // NewDate creates a new Date instance. 159 func NewDate(year, month, day int) Date { 160 return NewDateFromTime(NewUTCDay(year, time.Month(month), day)) 161 } 162 163 // ParseDate parses a formatted string into Date structure. 164 func ParseDate(s string) (*Date, error) { 165 tt, err := time.ParseInLocation("2006-01-02", s, time.UTC) 166 if err != nil { 167 return nil, err 168 } 169 date := NewDateFromTime(tt) 170 return &date, nil 171 } 172 173 // MarshalJSON implements the json.Marshaler interface. 174 // The time is a quoted string in ISO 8601 date format, with sub-second precision added if present. 175 func (d Date) MarshalJSON() ([]byte, error) { 176 if y := d.Year(); y < 0 || y >= 10000 { 177 return nil, errors.New("Date.MarshalJSON: year outside of range [0,9999]") 178 } 179 s := fmt.Sprintf(`"%04d-%02d-%02d"`, d.year, d.month, d.day) 180 return []byte(s), nil 181 } 182 183 // UnmarshalJSON implements the json.Unmarshaler interface. 184 // The date is expected to be a quoted string in ISO 8601 date format. 185 func (d *Date) UnmarshalJSON(data []byte) error { 186 s := string(data) 187 // Ignore null, like in the main JSON package. 188 if s == "null" { 189 return nil 190 } 191 // Check if length is equal to len(`"YYYY-MM-DD"`) == 12 192 if len(s) != 12 { 193 return errors.New("Date.UnmarshalJSON: incomplete date") 194 } 195 // Parse the YYYY-MM-DD part 196 dd, err := ParseDate(s[1:11]) 197 if err != nil { 198 return err 199 } 200 *d = *dd 201 return nil 202 } 203 204 // MarshalText implements the encoding.TextMarshaler interface. 205 // The time is formatted in ISO 8601 date format, with sub-second precision added if present. 206 func (d Date) MarshalText() (text []byte, err error) { 207 if y := d.Year(); y < 0 || y >= 10000 { 208 return nil, errors.New("Date.MarshalText: year outside of range [0,9999]") 209 } 210 s := fmt.Sprintf(`%04d-%02d-%02d`, d.year, d.month, d.day) 211 return []byte(s), nil 212 } 213 214 // UnmarshalText implements the encoding.TextUnmarshaler interface. 215 // The time is expected to be in ISO 8601 date format. 216 func (d *Date) UnmarshalText(text []byte) error { 217 // Parse the YYYY-MM-DD part 218 dd, err := ParseDate(string(text)) 219 if err != nil { 220 return err 221 } 222 *d = *dd 223 return nil 224 } 225 226 // Today returns the current date. 227 func Today() Date { 228 return NewDateFromTime(Now()) 229 } 230 231 // UTCToday returns the current date in UTC. 232 func UTCToday() Date { 233 return NewDateFromTime(UTCNow()) 234 } 235 236 // Yesterday returns the date of yesterday. 237 func Yesterday() Date { 238 return Today().AddDay(-1) 239 } 240 241 // UTCYesterday returns the date of yesterday in UTC. 242 func UTCYesterday() Date { 243 return UTCToday().AddDay(-1) 244 } 245 246 // Tomorrow returns the date of tomorrow. 247 func Tomorrow() Date { 248 return Today().AddDay(1) 249 } 250 251 // UTCTomorrow returns the date of tomorrow in UTC. 252 func UTCTomorrow() Date { 253 return UTCToday().AddDay(1) 254 } 255 256 // FirstDayOfYear returns the first day of current year. 257 func FirstDayOfYear() Date { 258 return Date{Now().Year(), 1, 1} 259 } 260 261 // LastDayOfYear returns the last day of current year. 262 func LastDayOfYear() Date { 263 return Date{Now().Year(), 12, 31} 264 } 265 266 // FirstDayOfMonth returns the first day of current month. 267 func FirstDayOfMonth() Date { 268 n := Now() 269 return Date{n.Year(), int(n.Month()), 1} 270 } 271 272 // LastDayOfMonth returns the last day of current month. 273 func LastDayOfMonth() Date { 274 return FirstDayOfMonth().AddMonth(1).AddDay(-1) 275 } 276 277 // ThisYear returns the year of current date. 278 func ThisYear() int { 279 return Now().Year() 280 } 281 282 // LastYear returns the year of last year. 283 func LastYear() int { 284 return ThisYear() - 1 285 } 286 287 // NextYear returns the year of next year. 288 func NextYear() int { 289 return ThisYear() + 1 290 }