github.com/diamondburned/arikawa/v2@v2.1.0/discord/time.go (about)

     1  package discord
     2  
     3  import (
     4  	"encoding/json"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  )
     9  
    10  // Timestamp has a valid zero-value, which can be checked using the IsValid()
    11  // method. This is useful for optional timestamps such as EditedTimestamp.
    12  type Timestamp time.Time
    13  
    14  const TimestampFormat = time.RFC3339 // same as ISO8601
    15  
    16  var (
    17  	_ json.Unmarshaler = (*Timestamp)(nil)
    18  	_ json.Marshaler   = (*Timestamp)(nil)
    19  )
    20  
    21  func NewTimestamp(t time.Time) Timestamp {
    22  	return Timestamp(t)
    23  }
    24  
    25  func NowTimestamp() Timestamp {
    26  	return NewTimestamp(time.Now())
    27  }
    28  
    29  // UnmarshalJSON parses a nullable RFC3339 string into time.
    30  func (t *Timestamp) UnmarshalJSON(v []byte) error {
    31  	str := strings.Trim(string(v), `"`)
    32  	if str == "null" {
    33  		return nil
    34  	}
    35  
    36  	r, err := time.Parse(TimestampFormat, str)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	*t = Timestamp(r)
    42  	return nil
    43  }
    44  
    45  // MarshalJSON returns null if Timestamp is not valid (zero). It returns the
    46  // time formatted in RFC3339 otherwise.
    47  func (t Timestamp) MarshalJSON() ([]byte, error) {
    48  	if !t.IsValid() {
    49  		return []byte("null"), nil
    50  	}
    51  
    52  	return []byte(`"` + t.Format(TimestampFormat) + `"`), nil
    53  }
    54  
    55  func (t Timestamp) IsValid() bool {
    56  	return !t.Time().IsZero()
    57  }
    58  
    59  func (t Timestamp) Format(fmt string) string {
    60  	return t.Time().Format(fmt)
    61  }
    62  
    63  func (t Timestamp) Time() time.Time {
    64  	return time.Time(t)
    65  }
    66  
    67  //
    68  
    69  type UnixTimestamp int64
    70  
    71  func (t UnixTimestamp) String() string {
    72  	return t.Time().String()
    73  }
    74  
    75  func (t UnixTimestamp) Time() time.Time {
    76  	return time.Unix(int64(t), 0)
    77  }
    78  
    79  //
    80  
    81  type UnixMsTimestamp int64
    82  
    83  func TimeToMilliseconds(t time.Time) UnixMsTimestamp {
    84  	return UnixMsTimestamp(t.UnixNano() / int64(time.Millisecond))
    85  }
    86  
    87  func (t UnixMsTimestamp) String() string {
    88  	return t.Time().String()
    89  }
    90  
    91  func (t UnixMsTimestamp) Time() time.Time {
    92  	return time.Unix(0, int64(t)*int64(time.Millisecond))
    93  }
    94  
    95  //
    96  
    97  type Seconds int
    98  
    99  // NullSecond is used in cases where null should be used instead of a number or
   100  // omitted. This is similar to NullSnowflake.
   101  const NullSecond = -1
   102  
   103  func DurationToSeconds(dura time.Duration) Seconds {
   104  	return Seconds(dura.Seconds())
   105  }
   106  
   107  func (s Seconds) MarshalJSON() ([]byte, error) {
   108  	if s < 1 {
   109  		return []byte("null"), nil
   110  	} else {
   111  		return []byte(strconv.Itoa(int(s))), nil
   112  	}
   113  }
   114  
   115  func (s Seconds) String() string {
   116  	return s.Duration().String()
   117  }
   118  
   119  func (s Seconds) Duration() time.Duration {
   120  	return time.Duration(s) * time.Second
   121  }
   122  
   123  //
   124  
   125  // Milliseconds is in float64 because some Discord events return time with a
   126  // trailing decimal.
   127  type Milliseconds float64
   128  
   129  func DurationToMilliseconds(dura time.Duration) Milliseconds {
   130  	return Milliseconds(dura.Milliseconds())
   131  }
   132  
   133  func (ms Milliseconds) String() string {
   134  	return ms.Duration().String()
   135  }
   136  
   137  func (ms Milliseconds) Duration() time.Duration {
   138  	const f64ms = Milliseconds(time.Millisecond)
   139  	return time.Duration(ms * f64ms)
   140  }