github.com/yaoapp/kun@v0.9.0/day/datetime.go (about) 1 package day 2 3 import ( 4 "database/sql/driver" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "strings" 9 "time" 10 "unicode" 11 ) 12 13 // Datetime type of day 14 type Datetime struct { 15 time.Time 16 } 17 18 var defaultLocation *time.Location = nil 19 20 var defaultFormats = []string{ 21 "2006-01-02T15:04:05-0700", 22 "2006-01-02T15:04:05.000Z", 23 "2006-01-02T15:04:05Z", 24 "2006-01-02T15:04:05+08:00", 25 "2006-01-02T15:04:05", 26 "2006-01-02 15:04:05", 27 "2006-01-02", 28 "15:04:05", 29 } 30 31 // Now is a alias of Make 32 func Now() *Datetime { 33 return Make() 34 } 35 36 // Make make a new Datetime 37 func Make() *Datetime { 38 now := &Datetime{Time: time.Now()} 39 if defaultLocation != nil { 40 now.Time = now.In(defaultLocation) 41 } 42 return now 43 } 44 45 // Of make a new datetime with the given value 46 func Of(value interface{}, formats ...string) *Datetime { 47 48 switch value.(type) { 49 case time.Time: 50 return &Datetime{Time: value.(time.Time)} 51 case *Datetime: 52 return value.(*Datetime) 53 case Datetime: 54 d := value.(Datetime) 55 return &d 56 } 57 58 if len(formats) == 0 { 59 formats = defaultFormats 60 } 61 valueStr := fmt.Sprintf("%v", value) 62 for _, format := range formats { 63 valueTime, err := time.Parse(format, valueStr) 64 if err == nil { 65 if defaultLocation != nil { 66 valueTime = valueTime.In(defaultLocation) 67 return &Datetime{Time: valueTime} 68 } 69 return &Datetime{Time: valueTime} 70 } 71 } 72 panic("the given value is not time format") 73 } 74 75 // Load load time with given format 76 func (d *Datetime) Load(value interface{}, formats ...string) *Datetime { 77 *d = *Of(value, formats...) 78 return d 79 } 80 81 // Timezone set the timezone of datetime 82 func (d *Datetime) Timezone(name string, offset ...int) *Datetime { 83 if len(offset) > 0 { 84 loc := time.FixedZone(name, offset[0]) 85 defaultLocation = loc 86 d.Time = d.In(loc) 87 return d 88 } 89 loc, err := time.LoadLocation(name) 90 if err != nil { 91 panic(err.Error()) 92 } 93 d.Time = d.In(loc) 94 return d 95 } 96 97 // GetTimezone get the timezone of current 98 func GetTimezone() (name string, offset int) { 99 if defaultLocation == nil { 100 return time.Now().Zone() 101 } 102 return time.Now().In(defaultLocation).Zone() 103 } 104 105 // TimezoneSystem using the system default zone 106 func TimezoneSystem() { 107 defaultLocation = nil 108 } 109 110 // TimezoneUTC using the UTC zone 111 func TimezoneUTC() { 112 defaultLocation = time.UTC 113 } 114 115 // Timezone set the default location 116 func Timezone(name string, offset ...int) { 117 if len(offset) > 0 { 118 loc := time.FixedZone(name, offset[0]) 119 defaultLocation = loc 120 return 121 } 122 123 loc, err := time.LoadLocation(name) 124 if err != nil { 125 panic(err.Error()) 126 } 127 defaultLocation = loc 128 } 129 130 // TimeZones Get a list of valid time zones 131 func TimeZones() []string { 132 var zones []string 133 var zoneDirs = []string{ 134 // Update path according to your OS 135 "/usr/share/zoneinfo/", 136 "/usr/share/lib/zoneinfo/", 137 "/usr/lib/locale/TZ/", 138 } 139 140 for _, zd := range zoneDirs { 141 zones = walkTzDir(zd, zones) 142 for idx, zone := range zones { 143 zones[idx] = strings.ReplaceAll(zone, zd+"/", "") 144 } 145 } 146 147 return zones 148 } 149 150 func walkTzDir(path string, zones []string) []string { 151 fileInfos, err := ioutil.ReadDir(path) 152 if err != nil { 153 return zones 154 } 155 156 isAlpha := func(s string) bool { 157 for _, r := range s { 158 if !unicode.IsLetter(r) { 159 return false 160 } 161 } 162 return true 163 } 164 165 for _, info := range fileInfos { 166 if info.Name() != strings.ToUpper(info.Name()[:1])+info.Name()[1:] { 167 continue 168 } 169 170 if !isAlpha(info.Name()[:1]) { 171 continue 172 } 173 174 newPath := path + "/" + info.Name() 175 176 if info.IsDir() { 177 zones = walkTzDir(newPath, zones) 178 } else { 179 zones = append(zones, newPath) 180 } 181 } 182 183 return zones 184 } 185 186 // Scan for db scan 187 func (d *Datetime) Scan(src interface{}) error { 188 *d = *Of(src) 189 return nil 190 } 191 192 // Value for db driver value 193 func (d *Datetime) Value() (driver.Value, error) { 194 return d.Time, nil 195 } 196 197 // MarshalJSON for json marshalJSON 198 func (d *Datetime) MarshalJSON() ([]byte, error) { 199 return json.Marshal(d.Time) 200 } 201 202 // UnmarshalJSON for json marshalJSON 203 func (d *Datetime) UnmarshalJSON(data []byte) error { 204 *d = *Of(data) 205 return nil 206 }