github.com/fraugster/parquet-go@v0.12.0/int96_time.go (about)

     1  package goparquet
     2  
     3  import (
     4  	"encoding/binary"
     5  	"time"
     6  )
     7  
     8  const (
     9  	jan011970 = 2440588
    10  	secPerDay = 24 * 60 * 60
    11  )
    12  
    13  var (
    14  	tsUnixEpoch = time.Unix(0, 0)
    15  )
    16  
    17  func timeToJD(t time.Time) (uint32, uint64) {
    18  	days := t.Unix() / secPerDay
    19  	nSecs := t.UnixNano() - (days * secPerDay * int64(time.Second))
    20  
    21  	// unix time starts from Jan 1, 1970 AC, this day is 2440588 day after the Jan 1, 4713 BC
    22  	return uint32(days) + jan011970, uint64(nSecs)
    23  }
    24  
    25  func jdToTime(jd uint32, nsec uint64) time.Time {
    26  	sec := int64(jd-jan011970) * secPerDay
    27  	return time.Unix(sec, int64(nsec))
    28  }
    29  
    30  // Int96ToTime is a utility function to convert a Int96 Julian Date timestamp (https://en.wikipedia.org/wiki/Julian_day) to a time.Time.
    31  // Please be aware that this function is limited to timestamps after the Unix epoch (Jan 01 1970 00:00:00 UTC) and cannot
    32  // convert timestamps before that. The returned time does not contain a monotonic clock reading and is in the machine's current time zone.
    33  func Int96ToTime(parquetDate [12]byte) time.Time {
    34  	nano := binary.LittleEndian.Uint64(parquetDate[:8])
    35  	dt := binary.LittleEndian.Uint32(parquetDate[8:])
    36  
    37  	return jdToTime(dt, nano)
    38  }
    39  
    40  // TimeToInt96 is a utility function to convert a time.Time to an Int96 Julian Date timestamp (https://en.wikipedia.org/wiki/Julian_day).
    41  // Please be aware that this function is limited to timestamps after the Unix epoch (Jan 01 1970 00:00:00 UTC) and cannot convert
    42  // timestamps before that.
    43  func TimeToInt96(t time.Time) [12]byte {
    44  	var parquetDate [12]byte
    45  	days, nSecs := timeToJD(t)
    46  	binary.LittleEndian.PutUint64(parquetDate[:8], nSecs)
    47  	binary.LittleEndian.PutUint32(parquetDate[8:], days)
    48  
    49  	return parquetDate
    50  }
    51  
    52  // IsAfterUnixEpoch tests if a timestamp can be converted into Julian Day format, i.e. is it greater than 01-01-1970?
    53  // Timestamps before this when converted will be corrupted when read back.
    54  func IsAfterUnixEpoch(t time.Time) bool {
    55  	return t.After(tsUnixEpoch)
    56  }