localtime.go (3308B)
1 package toml 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/pelletier/go-toml/v2/unstable" 9 ) 10 11 // LocalDate represents a calendar day in no specific timezone. 12 type LocalDate struct { 13 Year int 14 Month int 15 Day int 16 } 17 18 // AsTime converts d into a specific time instance at midnight in zone. 19 func (d LocalDate) AsTime(zone *time.Location) time.Time { 20 return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, zone) 21 } 22 23 // String returns RFC 3339 representation of d. 24 func (d LocalDate) String() string { 25 return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) 26 } 27 28 // MarshalText returns RFC 3339 representation of d. 29 func (d LocalDate) MarshalText() ([]byte, error) { 30 return []byte(d.String()), nil 31 } 32 33 // UnmarshalText parses b using RFC 3339 to fill d. 34 func (d *LocalDate) UnmarshalText(b []byte) error { 35 res, err := parseLocalDate(b) 36 if err != nil { 37 return err 38 } 39 *d = res 40 return nil 41 } 42 43 // LocalTime represents a time of day of no specific day in no specific 44 // timezone. 45 type LocalTime struct { 46 Hour int // Hour of the day: [0; 24[ 47 Minute int // Minute of the hour: [0; 60[ 48 Second int // Second of the minute: [0; 60[ 49 Nanosecond int // Nanoseconds within the second: [0, 1000000000[ 50 Precision int // Number of digits to display for Nanosecond. 51 } 52 53 // String returns RFC 3339 representation of d. 54 // If d.Nanosecond and d.Precision are zero, the time won't have a nanosecond 55 // component. If d.Nanosecond > 0 but d.Precision = 0, then the minimum number 56 // of digits for nanoseconds is provided. 57 func (d LocalTime) String() string { 58 s := fmt.Sprintf("%02d:%02d:%02d", d.Hour, d.Minute, d.Second) 59 60 if d.Precision > 0 { 61 s += fmt.Sprintf(".%09d", d.Nanosecond)[:d.Precision+1] 62 } else if d.Nanosecond > 0 { 63 // Nanoseconds are specified, but precision is not provided. Use the 64 // minimum. 65 s += strings.Trim(fmt.Sprintf(".%09d", d.Nanosecond), "0") 66 } 67 68 return s 69 } 70 71 // MarshalText returns RFC 3339 representation of d. 72 func (d LocalTime) MarshalText() ([]byte, error) { 73 return []byte(d.String()), nil 74 } 75 76 // UnmarshalText parses b using RFC 3339 to fill d. 77 func (d *LocalTime) UnmarshalText(b []byte) error { 78 res, left, err := parseLocalTime(b) 79 if err == nil && len(left) != 0 { 80 err = unstable.NewParserError(left, "extra characters") 81 } 82 if err != nil { 83 return err 84 } 85 *d = res 86 return nil 87 } 88 89 // LocalDateTime represents a time of a specific day in no specific timezone. 90 type LocalDateTime struct { 91 LocalDate 92 LocalTime 93 } 94 95 // AsTime converts d into a specific time instance in zone. 96 func (d LocalDateTime) AsTime(zone *time.Location) time.Time { 97 return time.Date(d.Year, time.Month(d.Month), d.Day, d.Hour, d.Minute, d.Second, d.Nanosecond, zone) 98 } 99 100 // String returns RFC 3339 representation of d. 101 func (d LocalDateTime) String() string { 102 return d.LocalDate.String() + "T" + d.LocalTime.String() 103 } 104 105 // MarshalText returns RFC 3339 representation of d. 106 func (d LocalDateTime) MarshalText() ([]byte, error) { 107 return []byte(d.String()), nil 108 } 109 110 // UnmarshalText parses b using RFC 3339 to fill d. 111 func (d *LocalDateTime) UnmarshalText(data []byte) error { 112 res, left, err := parseLocalDateTime(data) 113 if err == nil && len(left) != 0 { 114 err = unstable.NewParserError(left, "extra characters") 115 } 116 if err != nil { 117 return err 118 } 119 120 *d = res 121 return nil 122 }