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  }