├── .circleci └── config.yml ├── .github └── release-drafter.yml ├── .gitignore ├── LICENSE ├── README.md ├── datetime.go ├── datetime_test.go ├── docs └── resources │ └── logo.png ├── errors.go ├── errors_test.go ├── formats.go ├── formatting.go ├── formatting_test.go ├── go.mod ├── go.sum ├── timezone.go ├── timezone_constants.go └── timezone_test.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: golang:1.17-alpine 7 | working_directory: /go/src/gostradamus 8 | steps: 9 | - checkout 10 | - run: go install github.com/bykof/gostradamus 11 | 12 | lint: 13 | docker: 14 | - image: golangci/golangci-lint:v1.43-alpine 15 | steps: 16 | - checkout 17 | - run: golangci-lint run 18 | 19 | test: 20 | docker: 21 | - image: golang:1.17 22 | working_directory: /go/src/gostradamus 23 | steps: 24 | - checkout 25 | - run: go test -v -race -cover -coverprofile coverage.txt -covermode=atomic ./... 26 | - run: bash <(curl -s https://codecov.io/bash) 27 | 28 | workflows: 29 | version: 2 30 | build_lint_test: 31 | jobs: 32 | - build 33 | - lint 34 | - test -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/apps/release-drafter 2 | template: | 3 | ## What’s Changed 4 | 5 | $CHANGES -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Michael Bykovski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Gostradamus logo 3 |

4 | 5 | # Gostradamus: Better DateTimes for Go 6 | 7 | [![Gostradamus](https://img.shields.io/circleci/build/github/bykof/gostradamus)](https://app.circleci.com/pipelines/github/bykof/gostradamus) 8 | [![Go Report Card](https://goreportcard.com/badge/github.com/bykof/gostradamus)](https://goreportcard.com/report/github.com/bykof/gostradamus) 9 | [![codecov](https://codecov.io/gh/bykof/gostradamus/branch/master/graph/badge.svg)](https://codecov.io/gh/bykof/gostradamus) 10 | [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) 11 | [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/bykof/gostradamus) 12 | 13 | ## Introduction 14 | 15 | Gostradamus is a Go library that offers a lightweight and human-friendly way to create, transform, format, and parse 16 | datetimes. 17 | It uses the underlying Go `time` library and the main gostradamus' type `DateTime` can be easily converted to and 18 | from `time.Time`. 19 | 20 | Gostradamus is named after the french pharmacist [Nostradamus](https://en.wikipedia.org/wiki/Nostradamus). 21 | He is known for his prophecies, therefore he worked a lot with time, like Gostradamus. 22 | 23 | ## Features 24 | 25 | ✅ Easy conversion between `time.Time` and `gostradamus.DateTime` 26 | 27 | ✅ Format with common and known format tokens like `YYYY-MM-DD HH:mm:ss` 28 | 29 | ✅ Generates time spans, floors, ceilings from second to year (weeks included) 30 | 31 | ✅ Weeks manipulation and helper functions 32 | 33 | ✅ Timezone-aware with conversion 34 | 35 | ✅ Fully tested and ready for production 36 | 37 | ## Basic Usage 38 | 39 | ```go 40 | package main 41 | 42 | import "github.com/bykof/gostradamus" 43 | 44 | func main() { 45 | // Easy parsing 46 | dateTime, err := gostradamus.Parse("14.07.2017 02:40:00", "DD.MM.YYYY HH:mm:ss") 47 | if err != nil { 48 | panic(err) 49 | } 50 | 51 | // Easy manipulation 52 | dateTime = dateTime.ShiftMonths(-5).ShiftDays(2) 53 | 54 | // Easy formatting 55 | println(dateTime.Format("DD.MM.YYYY HH:mm:ss")) 56 | // 16.02.2017 02:40:00 57 | 58 | // Easy helper functions 59 | start, end := dateTime.SpanWeek() 60 | 61 | println(start.String(), end.String()) 62 | // 2017-02-13T00:00:00.000000Z 2017-02-19T23:59:59.999999Z 63 | } 64 | ``` 65 | 66 | ## Table of Contents 67 | 68 | + [Types](#types) 69 | + [Conversion between time.Time and gostradamus.DateTime](#conversion-between-timetime-and-gostradamusdatetime) 70 | + [Creation](#creation) 71 | + [Timezones](#timezones) 72 | + [Shift](#shift) 73 | + [Replace](#replace) 74 | + [Token Table](#token-table) 75 | + [Parsing](#parsing) 76 | + [Formatting](#formatting) 77 | + [Floor](#floor) 78 | + [Ceil](#ceil) 79 | + [Spans](#spans) 80 | + [Utils](#utils) 81 | - [IsBetween](#isBetween) 82 | - [IsoCalendar](#isoCalendar) 83 | + [Contribution](#contribution) 84 | + [License](#license) 85 | 86 | ## Usage 87 | 88 | This part introduces all basic features of gostradamus. 89 | Surely there are more, just look them up in 90 | the [offical documentation](https://pkg.go.dev/github.com/bykof/gostradamus?tab=doc). 91 | 92 | ## Types 93 | 94 | There are two types in this package, which are important to know: 95 | 96 | ```go 97 | type DateTime time.Time 98 | type Timezone string 99 | ``` 100 | 101 | `DateTime` contains all the creation, transforming, formatting and parsing functions. 102 | 103 | `Timezone` is just a string type but gostradamus has all timezones defined as constants. 104 | Look [here](https://github.com/bykof/gostradamus/blob/master/timezone_constants.go). 105 | 106 | ## Conversion between time.Time and gostradamus.DateTime 107 | 108 | You can easily convert between gostradamus.DateTime and time.Time package. 109 | Either with helper functions or with golang's [type conversion](https://tour.golang.org/basics/13) 110 | 111 | ```go 112 | import "time" 113 | 114 | // From gostradamus.DateTime to time.Time 115 | dateTime := gostradamus.Now() 116 | firstTime := dateTime.Time() 117 | secondTime := time.Time(dateTime) 118 | 119 | // From time.Time to gostradamus.DateTime 120 | t := time.Now() 121 | dateTime = gostradamus.DateTimeFromTime(t) 122 | dateTime = gostradamus.DateTime(t) 123 | ``` 124 | 125 | ## Creation 126 | 127 | If you want to create a gostradamus.DateTime you have several ways: 128 | 129 | Just create the DateTime from scratch: 130 | 131 | ```go 132 | // Create it with a defined timezone as you know it 133 | dateTime := gostradamus.NewDateTime(2020, 1, 1, 12, 0, 0, 0, gostradamus.EuropeBerlin) 134 | 135 | // Create it with predefined UTC timezone 136 | dateTime := gostradamus.NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0) 137 | 138 | // Create it with local timzone 139 | dateTime := gostradamus.NewLocalDateTime(2020, 1, 1, 12, 0, 0, 0) 140 | ``` 141 | 142 | Or create a DateTime from an ISO-8601 format: 143 | 144 | ```go 145 | dateTime := gostradamus.Parse("2017-07-14T02:40:00.000000+0200", gostradamus.Iso8601) 146 | ``` 147 | 148 | Or from a custom format: 149 | 150 | ```go 151 | dateTime := gostradamus.Parse("10.02.2010 14:59:53", "DD.MM.YYYY HH:mm:ss") 152 | ``` 153 | 154 | Or an UNIX timestamp for example: 155 | 156 | ```go 157 | dateTime := gostradamus.FromUnixTimestamp(1500000000) 158 | ``` 159 | 160 | Or different ways of the current datetime: 161 | 162 | ```go 163 | // Current DateTime in local timezone 164 | dateTime := gostradamus.Now() 165 | 166 | // Current DateTime in UTC timezone 167 | dateTime = gostradamus.UTCNow() 168 | 169 | // Current DateTime in given timezone 170 | dateTime = gostradamus.NowInTimezone(gostradamus.EuropeParis) 171 | ``` 172 | 173 | ## Timezones 174 | 175 | Feel free to use all available timezones, 176 | defined [here](https://github.com/bykof/gostradamus/blob/master/timezone_constants.go): 177 | 178 | ```go 179 | gostradamus.EuropeParis // Europe/Paris 180 | gostradamus.EuropeBerlin // Europe/Berlin 181 | gostradamus.AmericaNewYork // America/New_York 182 | ... and many more 183 | ``` 184 | 185 | Convert between timezones easily: 186 | 187 | ```go 188 | dateTime := gostradamus.NewUTC(2020, 1, 1, 12, 12, 12, 0).InTimezone(gostradamus.EuropeBerlin) 189 | println(dateTime.String()) 190 | // 2020-02-15T13:12:12.000000+0100 191 | 192 | dateTime = dateTime.InTimeZone(America_New_York) 193 | println(dateTime.String()) 194 | // 2020-02-15T07:12:12.000000-0500 195 | ``` 196 | 197 | ## Shift 198 | 199 | Shifting helps you to add or subtract years, months, days, hours, minutes, seconds, milliseconds, microseconds, and 200 | nanoseconds. 201 | 202 | To add a value use positive integer, to subtract use negative integer. 203 | 204 | ```go 205 | dateTime := gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 206 | dateTime = dateTime.ShiftYears(10) 207 | println(dateTime.String()) 208 | // 2030-01-01T01:01:01.000000+0000 209 | 210 | dateTime = gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 211 | dateTime = dateTime.ShiftDays(-10) 212 | println(dateTime.String()) 213 | // 2019-12-22T01:01:01.000000+0000 214 | 215 | dateTime = gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 216 | dateTime = dateTime.ShiftWeeks(2) 217 | println(dateTime.String()) 218 | // 2020-01-15T01:01:01.000000+0000 219 | 220 | dateTime = gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 221 | dateTime = dateTime.Shift(0, 1, 10, 0, 0, 0, 0) 222 | println(dateTime.String()) 223 | // 2020-02-11T01:01:01.000000+0000 224 | ``` 225 | 226 | ## Replace 227 | 228 | Replacing values can be done easily. 229 | 230 | ```go 231 | dateTime := gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 232 | dateTime = dateTime.ReplaceYear(2010) 233 | println(dateTime.String()) 234 | // 2010-01-01T01:01:01.000000+0000 235 | 236 | dateTime = gostradamus.NewUTCDateTime(2020, 1, 1, 1, 1, 1, 1) 237 | dateTime = dateTime.ReplaceYear(2010).ReplaceMonth(2) 238 | println(dateTime.String()) 239 | // 2010-02-01T01:01:01.000000+0000 240 | ``` 241 | 242 | ## Token Table 243 | 244 | | | Token | Output | 245 | |----------------|---------|-------------------------------------------| 246 | | Year | YYYY | 2000, 2001, 2002 … 2012, 2013 | 247 | | | YY | 00, 01, 02 … 12, 13 | 248 | | Month | MMMM | January, February, March … | 249 | | | MMM | Jan, Feb, Mar … | 250 | | | MM | 01, 02, 03 … 11, 12 | 251 | | | M | 1, 2, 3 … 11, 12 | 252 | | Day of Year | DDDD | 001, 002, 003 … 364, 365 | 253 | | Day of Month | DD | 01, 02, 03 … 30, 31 | 254 | | | D | 1, 2, 3 … 30, 31 | 255 | | | Do | 1st, 2nd, 3rd … | 256 | | Day of Week | dddd | Monday, Tuesday, Wednesday … | 257 | | | ddd | Mon, Tue, Wed … | 258 | | Hour | HH | 00, 01, 02 … 23, 24 | 259 | | | hh | 01, 02, 03 … 11, 12 | 260 | | | h | 1, 2, 3 … 11, 12 | 261 | | AM / PM | A | AM, PM | 262 | | | a | am, pm | 263 | | Minute | mm | 00, 01, 02 … 58, 59 | 264 | | | m | 0, 1, 2 … 58, 59 | 265 | | Second | ss | 00, 01, 02 … 58, 59 | 266 | | | s | 0, 1, 2 … 58, 59 | 267 | | Microsecond | S | 000000 … 999999 | 268 | | Timezone | ZZZ | Asia/Baku, Europe/Warsaw, GMT | 269 | | | zz | -07:00, -06:00 … +06:00, +07:00, +08, Z | 270 | | | Z | -0700, -0600 … +0600, +0700, +08, Z | 271 | 272 | ## Parsing 273 | 274 | > Please consider that you cannot put custom tokens or custom letters into the *parsing* string 275 | 276 | Easily parse with `Parse`: 277 | 278 | ```go 279 | dateTime, err := gostradamus.Parse("10.02.2010 14:59:53", "DD.MM.YYYY HH:mm:ss") 280 | println(dateTime.String()) 281 | // 2010-02-10T14:59:53.000000Z 282 | ``` 283 | 284 | You can also specify a timezone while parsing: 285 | 286 | ```go 287 | dateTime, err := gostradamus.ParseInTimezone("10.02.2010 14:59:53", "DD.MM.YYYY HH:mm:ss", gostradamus.EuropeBerlin) 288 | println(dateTime.String()) 289 | // 2010-02-10T14:59:53.000000+0100 290 | ``` 291 | 292 | ## Formatting 293 | 294 | Formatting is as easy as parsing: 295 | 296 | ```go 297 | dateTimeString := gostradamus.NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).Format("DD.MM.YYYY Time: HH:mm:ss") 298 | println(dateTimeString) 299 | // 14.07.2017 Time: 02:40:00 300 | ``` 301 | 302 | ## Floor 303 | 304 | ```go 305 | dateTimeString := gostradamus.NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).FloorDay() 306 | println(dateTimeString.String()) 307 | // 2017-07-14T00:00:00.000000Z 308 | 309 | dateTimeString := gostradamus.NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).FlorHour() 310 | println(dateTimeString.String()) 311 | // 2017-07-14T02:00:00.000000Z 312 | ``` 313 | 314 | ## Ceil 315 | 316 | ```go 317 | dateTimeString := gostradamus.NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).CeilMonth() 318 | println(dateTimeString.String()) 319 | // 2017-07-31T23:59:59.999999Z 320 | 321 | dateTimeString := gostradamus.NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).CeilSecond() 322 | println(dateTimeString.String()) 323 | // 2017-07-14T02:40:00.999999Z 324 | ``` 325 | 326 | ## Spans 327 | 328 | Spans can help you to get quickly the current span of the month or the day: 329 | 330 | ```go 331 | start, end := NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).SpanMonth() 332 | println(start.String()) 333 | // 2017-07-01T00:00:00.000000Z 334 | println(end.String()) 335 | // 2017-07-31T23:59:59.999999Z 336 | 337 | start, end = NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC).SpanDay() 338 | println(start.String()) 339 | // 2017-07-14T00:00:00.000000Z 340 | println(end.String()) 341 | // 2017-07-14T23:59:59.999999Z 342 | 343 | start, end = NewDateTime(2012, 12, 12, 2, 40, 0, 0, UTC).SpanWeek() 344 | println(start.String()) 345 | // 2012-12-10T00:00:00.000000Z 346 | println(end.String()) 347 | // 2012-12-16T23:59:59.999999Z 348 | ``` 349 | 350 | ## Utils 351 | 352 | Here is the section for some nice helper functions that will save you some time. 353 | 354 | ### IsBetween 355 | 356 | ```go 357 | isBetween := gostradamus.NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).IsBetween( 358 | gostradamus.NewUTCDateTime(2020, 1, 1, 11, 0, 0, 0), 359 | gostradamus.NewUTCDateTime(2020, 1, 1, 13, 0, 0, 0), 360 | ) 361 | println(isBetween) 362 | // true 363 | 364 | isBetween = gostradamus.NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).IsBetween( 365 | gostradamus.NewUTCDateTime(2020, 1, 1, 13, 0, 0, 0), 366 | gostradamus.NewUTCDateTime(2020, 1, 1, 14, 0, 0, 0), 367 | ) 368 | println(isBetween) 369 | // false 370 | ``` 371 | 372 | ### IsoCalendar 373 | 374 | Retrieve year, month, day directly as a 3-tuple: 375 | 376 | ```go 377 | year, month, day := gostradamus.NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).IsoCalendar() 378 | println(year, month, day) 379 | // 2020 1 1 380 | ``` 381 | 382 | ## Contribution 383 | 384 | Do you have an idea to improve Gostradamus? -> [Create an issue](https://github.com/bykof/gostradamus/issues/new/choose) 385 | 386 | Do you have already coded something for Gostradamus? -> Create a pull request. 387 | 388 | Did you discover a bug? -> [Create an issue](https://github.com/bykof/gostradamus/issues/new/choose) 389 | 390 | Otherwise feel free to contact me: `michael@bykovski.de` or visit my webpage: [bykovski.de](https://bykovski.de) 391 | 392 | ## License 393 | 394 | MIT licensed. See the LICENSE file for details. 395 | 396 | 397 | 398 | 399 | 400 | -------------------------------------------------------------------------------- /datetime.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // WeekInDays is the integer value how many days a week has 9 | const WeekInDays = 7 10 | 11 | // DateTime reflects time.Time and adds functionality of this library 12 | type DateTime time.Time 13 | 14 | // DateTimeFromTime returns a DateTime with given time.Time 15 | func DateTimeFromTime(time time.Time) DateTime { 16 | return DateTime(time) 17 | } 18 | 19 | // NewDateTime returns a new DateTime in the timezone given 20 | func NewDateTime( 21 | year int, 22 | month int, 23 | day int, 24 | hour int, 25 | minute int, 26 | second int, 27 | nanosecond int, 28 | timezone Timezone, 29 | ) DateTime { 30 | return DateTimeFromTime( 31 | time.Date( 32 | year, 33 | time.Month(month), 34 | day, 35 | hour, 36 | minute, 37 | second, 38 | nanosecond, 39 | timezone.Location(), 40 | ), 41 | ) 42 | } 43 | 44 | // NewUTCDateTime returns a new DateTime with timezone in UTC 45 | func NewUTCDateTime( 46 | year int, 47 | month int, 48 | day int, 49 | hour int, 50 | minute int, 51 | second int, 52 | nanosecond int, 53 | ) DateTime { 54 | return NewDateTime( 55 | year, 56 | month, 57 | day, 58 | hour, 59 | minute, 60 | second, 61 | nanosecond, 62 | UTC, 63 | ) 64 | } 65 | 66 | // NewLocalDateTime creates a new DateTime in Local (system) timezone 67 | func NewLocalDateTime( 68 | year int, 69 | month int, 70 | day int, 71 | hour int, 72 | minute int, 73 | second int, 74 | nanosecond int, 75 | ) DateTime { 76 | return NewDateTime( 77 | year, 78 | month, 79 | day, 80 | hour, 81 | minute, 82 | second, 83 | nanosecond, 84 | Local(), 85 | ) 86 | } 87 | 88 | // FromUnixTimestamp gets the DateTime from given unix timestamp. 89 | // The returned Datetime has the UTC timezone 90 | func FromUnixTimestamp(timestamp int64) DateTime { 91 | return DateTime(time.Unix(timestamp, 0).UTC()) 92 | } 93 | 94 | // Now returns the current local DateTime 95 | func Now() DateTime { 96 | return DateTimeFromTime(time.Now()) 97 | } 98 | 99 | // UTCNow returns the current DateTime in UTC timezone 100 | func UTCNow() DateTime { 101 | return Now().InTimezone(UTC) 102 | } 103 | 104 | // NowInTimezone returns the current DateTime in given timezone 105 | func NowInTimezone(timezone Timezone) DateTime { 106 | return Now().InTimezone(timezone) 107 | } 108 | 109 | // Year of current DateTime as int 110 | func (dt DateTime) Year() int { 111 | return dt.Time().Year() 112 | } 113 | 114 | // Month of current DateTime as int 115 | func (dt DateTime) Month() int { 116 | return int(dt.Time().Month()) 117 | } 118 | 119 | // Day of current DateTime as int 120 | func (dt DateTime) Day() int { 121 | return dt.Time().Day() 122 | } 123 | 124 | // Hour of current DateTime as int 125 | func (dt DateTime) Hour() int { 126 | return dt.Time().Hour() 127 | } 128 | 129 | // Minute of current DateTime as int 130 | func (dt DateTime) Minute() int { 131 | return dt.Time().Minute() 132 | } 133 | 134 | // Second of current DateTime as int 135 | func (dt DateTime) Second() int { 136 | return dt.Time().Second() 137 | } 138 | 139 | // Nanosecond of current DateTime as int 140 | func (dt DateTime) Nanosecond() int { 141 | return dt.Time().Nanosecond() 142 | } 143 | 144 | // Time returns the underlying time.Time of DateTime 145 | func (dt DateTime) Time() time.Time { 146 | return time.Time(dt) 147 | } 148 | 149 | // IsoFormat the current DateTime into ISO-8601 standard 150 | // 151 | // For Example: 152 | // 153 | // 2017-07-14T02:40:00.000000 154 | // 155 | func (dt DateTime) IsoFormat() string { 156 | return dt.Format(Iso8601) 157 | } 158 | 159 | // IsoFormatTZ the current DateTime into ISO-8601 standard and current timezone info 160 | // 161 | // For Example: 162 | // 163 | // 2017-07-14T02:40:00.000000+0200 164 | // 165 | func (dt DateTime) IsoFormatTZ() string { 166 | return dt.Format(Iso8601TZ) 167 | } 168 | 169 | // CTimeFormat the current DateTime to ctime standard 170 | // 171 | // Example: Sat Feb 15 12:12:12 2020 172 | // 173 | func (dt DateTime) CTimeFormat() string { 174 | return dt.Format(CTime) 175 | } 176 | 177 | // String of the DateTime 178 | // it will use the IsoFormat 179 | // It defines the ``native'' format for that value. 180 | // The String method is used to print values passed as an operand 181 | // to any format that accepts a string or to an unformatted printer 182 | // such as Print. 183 | func (dt DateTime) String() string { 184 | return dt.IsoFormatTZ() 185 | } 186 | 187 | // GoString of the DateTime 188 | // it will use the IsoFormat 189 | // The GoString method is used to print values passed as an operand to a %#v format. 190 | func (dt DateTime) GoString() string { 191 | return dt.IsoFormatTZ() 192 | } 193 | 194 | // Copy the current DateTime to a new DateTime 195 | func (dt DateTime) Copy() DateTime { 196 | return NewDateTime( 197 | dt.Year(), 198 | dt.Month(), 199 | dt.Day(), 200 | dt.Hour(), 201 | dt.Minute(), 202 | dt.Second(), 203 | dt.Nanosecond(), 204 | dt.Timezone(), 205 | ) 206 | } 207 | 208 | // Format the current DateTime with given format to a string 209 | func (dt DateTime) Format(format string) string { 210 | return formatFromTime(dt.Time(), format) 211 | } 212 | 213 | // Parse a string value with given format into a new DateTime 214 | func Parse(value string, format string) (DateTime, error) { 215 | parsedTime, err := parseToTime(value, format, UTC) 216 | return DateTimeFromTime(parsedTime), err 217 | } 218 | 219 | // ParseInTimezone a string value with given format into a new DateTime in given timezone 220 | func ParseInTimezone(value string, format string, timezone Timezone) (DateTime, error) { 221 | parsedTime, err := parseToTime(value, format, timezone) 222 | return DateTimeFromTime(parsedTime), err 223 | } 224 | 225 | // InTimezone sets the current DateTime in the given Timezone and returns a new DateTime 226 | func (dt DateTime) InTimezone(timezone Timezone) DateTime { 227 | return DateTimeFromTime(dt.Time().In(timezone.Location())) 228 | } 229 | 230 | // IsoCalendar returns three int values with (year, month, day) 231 | func (dt DateTime) IsoCalendar() (int, int, int) { 232 | return dt.Year(), dt.Month(), dt.Day() 233 | } 234 | 235 | // Timezone returns the Timezone of current DateTime object 236 | func (dt DateTime) Timezone() Timezone { 237 | return Timezone(dt.Time().Location().String()) 238 | } 239 | 240 | // UnixTimestamp returns the unix timestamp as int64 241 | func (dt DateTime) UnixTimestamp() int64 { 242 | return dt.Time().Unix() 243 | } 244 | 245 | // ShiftYears adds or subtracts years in current DateTime and returns a new DateTime 246 | // Add is a positive integer 247 | // Subtract is a negative integer 248 | func (dt DateTime) ShiftYears(years int) DateTime { 249 | return DateTimeFromTime(dt.Time().AddDate(years, 0, 0)) 250 | } 251 | 252 | // ShiftMonths adds or subtracts months 253 | // Add is a positive integer 254 | // Subtract is a negative integer 255 | func (dt DateTime) ShiftMonths(months int) DateTime { 256 | return DateTimeFromTime(dt.Time().AddDate(0, months, 0)) 257 | } 258 | 259 | // ShiftWeeks add or subtracts weeks 260 | // Add is a positive integer 261 | // Subtract is a negative integer 262 | func (dt DateTime) ShiftWeeks(weeks int) DateTime { 263 | return DateTimeFromTime(dt.Time().AddDate(0, 0, weeks*WeekInDays)) 264 | } 265 | 266 | // ShiftDays adds or subtracts days 267 | // Add is a positive integer 268 | // Subtract is a negative integer 269 | func (dt DateTime) ShiftDays(days int) DateTime { 270 | return DateTimeFromTime(dt.Time().AddDate(0, 0, days)) 271 | } 272 | 273 | // ShiftHours adds or subtracts hours 274 | // Add is a positive integer 275 | // Subtract is a negative integer 276 | func (dt DateTime) ShiftHours(hours int) DateTime { 277 | duration, _ := time.ParseDuration(fmt.Sprintf("%dh", hours)) 278 | return DateTime(dt.Time().Add(duration)) 279 | } 280 | 281 | // ShiftMinutes adds or subtracts minutes 282 | // Add is a positive integer 283 | // Subtract is a negative integer 284 | func (dt DateTime) ShiftMinutes(minutes int) DateTime { 285 | duration, _ := time.ParseDuration(fmt.Sprintf("%dm", minutes)) 286 | return DateTime(dt.Time().Add(duration)) 287 | } 288 | 289 | // ShiftSeconds adds or subtracts seconds 290 | // Add is a positive integer 291 | // Subtract is a negative integer 292 | func (dt DateTime) ShiftSeconds(second int) DateTime { 293 | duration, _ := time.ParseDuration(fmt.Sprintf("%ds", second)) 294 | return DateTime(dt.Time().Add(duration)) 295 | } 296 | 297 | // ShiftMilliSeconds adds or subtracts milliseconds 298 | // Add is a positive integer 299 | // Subtract is a negative integer 300 | func (dt DateTime) ShiftMilliSeconds(millisecond int) DateTime { 301 | duration, _ := time.ParseDuration(fmt.Sprintf("%dms", millisecond)) 302 | return DateTime(dt.Time().Add(duration)) 303 | } 304 | 305 | // ShiftMicroSeconds adds or subtracts microseconds 306 | // Add is a positive integer 307 | // Subtract is a negative integer 308 | func (dt DateTime) ShiftMicroSeconds(microsecond int) DateTime { 309 | duration, _ := time.ParseDuration(fmt.Sprintf("%dus", microsecond)) 310 | return DateTime(dt.Time().Add(duration)) 311 | } 312 | 313 | // ShiftNanoseconds adds or subtracts nanoseconds in current DateTime and returns a new DateTime 314 | // Add is a positive integer 315 | // Subtract is a negative integer 316 | func (dt DateTime) ShiftNanoseconds(nanosecond int) DateTime { 317 | duration, _ := time.ParseDuration(fmt.Sprintf("%dns", nanosecond)) 318 | return DateTime(dt.Time().Add(duration)) 319 | } 320 | 321 | // Shift adds or subtracts years, months, days, hours, minutes, seconds, and nanoseconds of current DateTime and returns a new DateTime 322 | // Add is a positive integer 323 | // Subtract is a negative integer 324 | func (dt DateTime) Shift(years int, months int, days int, hours int, minutes int, seconds int, nanoseconds int) DateTime { 325 | return dt.ShiftYears(years). 326 | ShiftMonths(months). 327 | ShiftDays(days). 328 | ShiftHours(hours). 329 | ShiftMinutes(minutes). 330 | ShiftSeconds(seconds). 331 | ShiftNanoseconds(nanoseconds) 332 | } 333 | 334 | // FloorYear returns a DateTime with all values to "floor" except year 335 | // 336 | // For Example: 337 | // 338 | // 2012-12-12 12:12:12.123456789 becomes 2012-01-01 00:00:00.00000000 339 | // 340 | func (dt DateTime) FloorYear() DateTime { 341 | return dt.Replace(dt.Year(), 1, 1, 0, 0, 0, 0) 342 | } 343 | 344 | // FloorMonth returns a DateTime with all values to "floor" except year, month 345 | // 346 | // For Example: 347 | // 348 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-01 00:00:00.00000000 349 | // 350 | func (dt DateTime) FloorMonth() DateTime { 351 | return dt.Replace(dt.Year(), dt.Month(), 1, 0, 0, 0, 0) 352 | } 353 | 354 | // FloorWeek returns a DateTime with all values to "floor" of current DateTime's week except year, month 355 | // 356 | // For Example: 357 | // 358 | // 2012-12-12 12:12:12.123456789 (wednesday) becomes 2012-12-10 00:00:00.000000000 (monday) 359 | // 360 | func (dt DateTime) FloorWeek() DateTime { 361 | deltaWeekdays := int(dt.WeekDay() - time.Monday) 362 | // currentWeekDay is already monday 363 | if deltaWeekdays == 0 { 364 | return dt.FloorDay() 365 | } 366 | 367 | if deltaWeekdays == -1 { 368 | return dt.ShiftDays(-6).FloorDay() 369 | } 370 | 371 | return dt.ShiftDays(-deltaWeekdays).FloorDay() 372 | 373 | } 374 | 375 | // FloorDay returns a DateTime with all values to "floor" except year, month, day 376 | // 377 | // For Example: 378 | // 379 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 00:00:00.00000000 380 | // 381 | func (dt DateTime) FloorDay() DateTime { 382 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), 0, 0, 0, 0) 383 | } 384 | 385 | // FloorHour returns a DateTime with all values to "floor" except year, month, day, hour 386 | // 387 | // For Example: 388 | // 389 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 12:00:00.00000000 390 | // 391 | func (dt DateTime) FloorHour() DateTime { 392 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), 0, 0, 0) 393 | } 394 | 395 | // FloorMinute returns a DateTime with all values to "floor" except year, month, day, hour, minute 396 | // 397 | // For Example: 398 | // 399 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 12:12:00.00000000 400 | // 401 | func (dt DateTime) FloorMinute() DateTime { 402 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), 0, 0) 403 | } 404 | 405 | // FloorSecond returns a DateTime with all values to "floor" except year, month, day, hour, minute, second 406 | // 407 | // For Example: 408 | // 409 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-31 12:12:12.00000000 410 | // 411 | func (dt DateTime) FloorSecond() DateTime { 412 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second(), 0) 413 | } 414 | 415 | // CeilYear returns a DateTime with all values to "ceil" except year 416 | // 417 | // For Example: 418 | // 419 | // 2012-05-12 12:12:12.123456789 becomes 2012-12-31 23:59:59.999999999 420 | // 421 | func (dt DateTime) CeilYear() DateTime { 422 | return dt.Replace(dt.Year(), 12, 31, 23, 59, 59, 999999999) 423 | } 424 | 425 | // CeilMonth returns a DateTime with all values to "ceil" except year, month 426 | // 427 | // For Example: 428 | // 429 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-31 23:59:59.999999999 430 | // 431 | func (dt DateTime) CeilMonth() DateTime { 432 | tempDateTime := dt.Copy() 433 | tempDateTime = tempDateTime.ShiftMonths(1) 434 | tempDateTime = tempDateTime.ReplaceDay(1) 435 | tempDateTime = tempDateTime.ShiftDays(-1) 436 | return dt.Replace(dt.Year(), dt.Month(), tempDateTime.Day(), 23, 59, 59, 999999999) 437 | } 438 | 439 | // CeilWeek returns a DateTime with all values to "ceil" of current DateTime's week except year, month 440 | // 441 | // For Example: 442 | // 443 | // 2012-12-12 12:12:12.123456789 (wednesday) becomes 2012-12-16 23:59:59:123456789 (sunday) 444 | // 445 | func (dt DateTime) CeilWeek() DateTime { 446 | currentWeekDay := int(dt.WeekDay()) 447 | if currentWeekDay == 0 { 448 | return dt.CeilDay() 449 | } 450 | 451 | return dt.ShiftDays(WeekInDays - currentWeekDay).CeilDay() 452 | } 453 | 454 | // CeilDay returns a DateTime with all values to "ceil" except year, month, day, minute, second 455 | // 456 | // For Example: 457 | // 458 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 23:59:59.999999999 459 | // 460 | func (dt DateTime) CeilDay() DateTime { 461 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), 23, 59, 59, 999999999) 462 | } 463 | 464 | // CeilHour returns a DateTime with all values to "ceil" except year, month, day, hour 465 | // 466 | // For Example: 467 | // 468 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 12:59:59.999999999 469 | // 470 | func (dt DateTime) CeilHour() DateTime { 471 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), 59, 59, 999999999) 472 | } 473 | 474 | // CeilMinute returns a DateTime with all values to "ceil" except year, month, day, hour, minute 475 | // 476 | // For Example: 477 | // 478 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 12:12:59.999999999 479 | // 480 | func (dt DateTime) CeilMinute() DateTime { 481 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), 59, 999999999) 482 | } 483 | 484 | // CeilSecond returns a DateTime with all values to "ceil" except year, month, day, hour, minute, second 485 | // 486 | // For Example: 487 | // 488 | // 2012-12-12 12:12:12.123456789 becomes 2012-12-12 12:12:12.999999999 489 | // 490 | func (dt DateTime) CeilSecond() DateTime { 491 | return dt.Replace(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second(), 999999999) 492 | } 493 | 494 | // SpanYear returns the start and end DateTime of current year span 495 | // 496 | // For Example: 497 | // 498 | // 2012-05-12 12:12:12:123456789 becomes (2012-01-01 00:00:00.000000000, 2012-12-31 23:59:59.999999999) 499 | // 500 | func (dt DateTime) SpanYear() (DateTime, DateTime) { 501 | return dt.FloorYear(), dt.CeilYear() 502 | } 503 | 504 | // SpanMonth returns the start and end DateTime of current month span 505 | // 506 | // For Example: 507 | // 508 | // 2012-12-12 12:12:12:123456789 becomes (2012-12-01 00:00:00.000000000, 2012-12-31 23:59:59.999999999) 509 | // 510 | func (dt DateTime) SpanMonth() (DateTime, DateTime) { 511 | return dt.FloorMonth(), dt.CeilMonth() 512 | } 513 | 514 | // SpanWeek returns the start and end DateTime of current week span 515 | // 516 | // For Example: 517 | // 518 | // 2012-12-12 12:12:12.123456789 becomes (2012-12-10 00:00:00.00000000, 2012-12-16 23:59:59.999999999) 519 | // 520 | func (dt DateTime) SpanWeek() (DateTime, DateTime) { 521 | return dt.FloorWeek(), dt.CeilWeek() 522 | } 523 | 524 | // SpanDay returns the start and end DateTime of current day span 525 | // 526 | // For Example: 527 | // 528 | // 2012-12-12 12:12:12:123456789 becomes (2012-12-12 00:00:00.000000000, 2012-12-12 23:59:59.999999999) 529 | // 530 | func (dt DateTime) SpanDay() (DateTime, DateTime) { 531 | return dt.FloorDay(), dt.CeilDay() 532 | } 533 | 534 | // SpanHour returns the start and end DateTime of current hour span 535 | // 536 | // For Example: 537 | // 538 | // 2012-12-12 12:12:12:123456789 becomes (2012-12-12 12:00:00.000000000, 2012-12-12 12:59:59.999999999) 539 | // 540 | func (dt DateTime) SpanHour() (DateTime, DateTime) { 541 | return dt.FloorHour(), dt.CeilHour() 542 | } 543 | 544 | // SpanMinute returns the start and end DateTime of current minute span 545 | // 546 | // For Example: 547 | // 548 | // 2012-12-12 12:12:12:123456789 becomes (2012-12-12 12:12:00.000000000, 2012-12-12 12:12:59.999999999) 549 | // 550 | func (dt DateTime) SpanMinute() (DateTime, DateTime) { 551 | return dt.FloorMinute(), dt.CeilMinute() 552 | } 553 | 554 | // SpanSecond returns the start and end DateTime of current second span 555 | // 556 | // For Example: 557 | // 558 | // 2012-12-12 12:12:12:123456789 becomes (2012-12-12 12:12:12.000000000, 2012-12-12 12:12:12.999999999) 559 | // 560 | func (dt DateTime) SpanSecond() (DateTime, DateTime) { 561 | return dt.FloorSecond(), dt.CeilSecond() 562 | } 563 | 564 | // WeekDay returns time.Weekday 565 | func (dt DateTime) WeekDay() time.Weekday { 566 | return dt.Time().Weekday() 567 | } 568 | 569 | // ReplaceYear will set the year of current DateTime and returns a new DateTime 570 | func (dt DateTime) ReplaceYear(year int) DateTime { 571 | return NewDateTime( 572 | year, 573 | dt.Month(), 574 | dt.Day(), 575 | dt.Hour(), 576 | dt.Minute(), 577 | dt.Second(), 578 | dt.Nanosecond(), 579 | dt.Timezone(), 580 | ) 581 | } 582 | 583 | // ReplaceMonth will set the month of current DateTime and returns a new DateTime 584 | func (dt DateTime) ReplaceMonth(month int) DateTime { 585 | return NewDateTime( 586 | dt.Year(), 587 | month, 588 | dt.Day(), 589 | dt.Hour(), 590 | dt.Minute(), 591 | dt.Second(), 592 | dt.Nanosecond(), 593 | dt.Timezone(), 594 | ) 595 | } 596 | 597 | // ReplaceDay will set the day of current DateTime and returns a new DateTime 598 | func (dt DateTime) ReplaceDay(day int) DateTime { 599 | return NewDateTime( 600 | dt.Year(), 601 | dt.Month(), 602 | day, 603 | dt.Hour(), 604 | dt.Minute(), 605 | dt.Second(), 606 | dt.Nanosecond(), 607 | dt.Timezone(), 608 | ) 609 | } 610 | 611 | // ReplaceHour will set the hour of current DateTime and returns a new DateTime 612 | func (dt DateTime) ReplaceHour(hour int) DateTime { 613 | return NewDateTime( 614 | dt.Year(), 615 | dt.Month(), 616 | dt.Day(), 617 | hour, 618 | dt.Minute(), 619 | dt.Second(), 620 | dt.Nanosecond(), 621 | dt.Timezone(), 622 | ) 623 | } 624 | 625 | // ReplaceMinute will set the minute of current DateTime and returns a new DateTime 626 | func (dt DateTime) ReplaceMinute(minute int) DateTime { 627 | return NewDateTime( 628 | dt.Year(), 629 | dt.Month(), 630 | dt.Day(), 631 | dt.Hour(), 632 | minute, 633 | dt.Second(), 634 | dt.Nanosecond(), 635 | dt.Timezone(), 636 | ) 637 | } 638 | 639 | // ReplaceSecond will set the second of current DateTime and returns a new DateTime 640 | func (dt DateTime) ReplaceSecond(second int) DateTime { 641 | return NewDateTime( 642 | dt.Year(), 643 | dt.Month(), 644 | dt.Day(), 645 | dt.Hour(), 646 | dt.Minute(), 647 | second, 648 | dt.Nanosecond(), 649 | dt.Timezone(), 650 | ) 651 | } 652 | 653 | // ReplaceNanosecond will set the nanosecond of current DateTime and returns a new DateTime 654 | func (dt DateTime) ReplaceNanosecond(nanosecond int) DateTime { 655 | return NewDateTime( 656 | dt.Year(), 657 | dt.Month(), 658 | dt.Day(), 659 | dt.Hour(), 660 | dt.Minute(), 661 | dt.Second(), 662 | nanosecond, 663 | dt.Timezone(), 664 | ) 665 | } 666 | 667 | // Replace will set the year, month, day, hour, minute, second, and nanosecond of current DateTime and returns a new DateTime 668 | func (dt DateTime) Replace(year int, month int, day int, hour int, minute int, second int, nanosecond int) DateTime { 669 | return dt.ReplaceYear(year). 670 | ReplaceMonth(month). 671 | ReplaceDay(day). 672 | ReplaceHour(hour). 673 | ReplaceMinute(minute). 674 | ReplaceSecond(second). 675 | ReplaceNanosecond(nanosecond) 676 | } 677 | 678 | // IsBetween checks if current DateTime is between start and end DateTimes 679 | func (dt DateTime) IsBetween(start DateTime, end DateTime) bool { 680 | return dt.Time().After(start.Time()) && dt.Time().Before(end.Time()) 681 | } 682 | -------------------------------------------------------------------------------- /datetime_test.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestParse(t *testing.T) { 10 | actual, err := Parse("10.02.2010 14:59:53", "DD.MM.YYYY HH:mm:ss") 11 | assert.NoError(t, err) 12 | assert.Equal(t, actual, NewUTCDateTime(2010, 2, 10, 14, 59, 53, 0)) 13 | 14 | actual, err = Parse("2017-07-14T02:40:00.000000", Iso8601) 15 | assert.NoError(t, err) 16 | assert.Equal(t, NewDateTime(2017, 7, 14, 2, 40, 0, 0, UTC), actual) 17 | } 18 | 19 | func TestParseInTimezone(t *testing.T) { 20 | actual, err := ParseInTimezone("2017-07-14T02:40:00.000000+0200", Iso8601TZ, EuropeBerlin) 21 | assert.NoError(t, err) 22 | assert.Equal( 23 | t, 24 | NewDateTime(2017, 7, 14, 2, 40, 0, 0, EuropeBerlin), 25 | actual, 26 | ) 27 | } 28 | 29 | func TestDateTime_ShiftMilliSeconds(t *testing.T) { 30 | dateTime := NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMilliSeconds(10) 31 | assert.Equal( 32 | t, 33 | NewUTCDateTime(2020, 1, 1, 12, 0, 0, 10000000), 34 | dateTime, 35 | ) 36 | 37 | dateTime = NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMilliSeconds(0) 38 | assert.Equal( 39 | t, 40 | NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0), 41 | dateTime, 42 | ) 43 | 44 | dateTime = NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMilliSeconds(-20) 45 | assert.Equal( 46 | t, 47 | NewUTCDateTime(2020, 1, 1, 11, 59, 59, 980000000), 48 | dateTime, 49 | ) 50 | } 51 | 52 | func TestDateTime_ShiftMicroSeconds(t *testing.T) { 53 | dateTime := NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMicroSeconds(10) 54 | assert.Equal( 55 | t, 56 | NewUTCDateTime(2020, 1, 1, 12, 0, 0, 10000), 57 | dateTime, 58 | ) 59 | 60 | dateTime = NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMicroSeconds(0) 61 | assert.Equal( 62 | t, 63 | NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0), 64 | dateTime, 65 | ) 66 | 67 | dateTime = NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).ShiftMicroSeconds(-20) 68 | assert.Equal( 69 | t, 70 | NewUTCDateTime(2020, 1, 1, 11, 59, 59, 999980000), 71 | dateTime, 72 | ) 73 | } 74 | 75 | func TestDateTime_Shift(t *testing.T) { 76 | dateTime := NewUTCDateTime(2020, 1, 1, 12, 0, 1, 0).Shift( 77 | 10, 78 | 2, 79 | -3, 80 | -2, 81 | 20, 82 | 12, 83 | -20, 84 | ) 85 | assert.Equal( 86 | t, 87 | NewUTCDateTime(2030, 2, 26, 10, 20, 12, 999999980), 88 | dateTime, 89 | ) 90 | } 91 | 92 | func TestDateTime_Replace(t *testing.T) { 93 | dateTime := NewUTCDateTime(2020, 1, 1, 12, 0, 1, 0).Replace( 94 | 2030, 95 | 2, 96 | 26, 97 | 10, 98 | 20, 99 | 12, 100 | 999999980, 101 | ) 102 | assert.Equal( 103 | t, 104 | NewUTCDateTime(2030, 2, 26, 10, 20, 12, 999999980), 105 | dateTime, 106 | ) 107 | } 108 | 109 | func TestDateTime_WithTimezone(t *testing.T) { 110 | 111 | } 112 | 113 | func TestDateTime_Timezone(t *testing.T) { 114 | dateTime := NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0) 115 | assert.Equal(t, dateTime.Timezone(), UTC) 116 | } 117 | 118 | func TestFromUnixTimestamp(t *testing.T) { 119 | timestamp := int64(1500000000) 120 | actual := FromUnixTimestamp(timestamp) 121 | assert.Equal(t, NewUTCDateTime(2017, 7, 14, 2, 40, 0, 0), actual) 122 | } 123 | 124 | func TestDateTime_UnixTimestamp(t *testing.T) { 125 | actual := NewUTCDateTime(2017, 7, 14, 2, 40, 0, 0).UnixTimestamp() 126 | assert.Equal(t, actual, int64(1500000000)) 127 | } 128 | 129 | func TestDateTime_ForJson(t *testing.T) { 130 | actual := NewUTCDateTime(2017, 7, 14, 2, 40, 0, 0).UnixTimestamp() 131 | assert.Equal(t, actual, int64(1500000000)) 132 | } 133 | 134 | func TestNewLocalDateTime(t *testing.T) { 135 | actual := NewLocalDateTime(2017, 7, 14, 0, 40, 0, 0) 136 | _, offset := actual.Time().Zone() 137 | assert.Equal( 138 | t, 139 | actual, 140 | NewUTCDateTime(2017, 7, 14, actual.Hour()-(offset/3600), 40, 0, 0).InTimezone(Local()), 141 | ) 142 | } 143 | 144 | func TestDateTime_IsoFormat(t *testing.T) { 145 | actual := NewDateTime(2017, 7, 14, 2, 40, 0, 0, EuropeBerlin).IsoFormat() 146 | assert.Equal(t, actual, "2017-07-14T02:40:00.000000") 147 | } 148 | 149 | func TestDateTime_String(t *testing.T) { 150 | actual := NewDateTime(2017, 7, 14, 2, 40, 0, 0, EuropeBerlin).String() 151 | assert.Equal(t, actual, "2017-07-14T02:40:00.000000+0200") 152 | } 153 | 154 | func TestDateTime_GoString(t *testing.T) { 155 | actual := NewDateTime(2017, 7, 14, 2, 40, 0, 0, EuropeBerlin).GoString() 156 | assert.Equal(t, actual, "2017-07-14T02:40:00.000000+0200") 157 | } 158 | 159 | func TestDateTime_IsBetween(t *testing.T) { 160 | actual := NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).IsBetween( 161 | NewUTCDateTime(2020, 1, 1, 11, 0, 0, 0), 162 | NewUTCDateTime(2020, 1, 1, 13, 0, 0, 0), 163 | ) 164 | assert.True(t, actual) 165 | 166 | actual = NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).IsBetween( 167 | NewUTCDateTime(2020, 1, 1, 13, 0, 0, 0), 168 | NewUTCDateTime(2020, 1, 1, 14, 0, 0, 0), 169 | ) 170 | assert.False(t, actual) 171 | } 172 | 173 | func TestDateTime_WeekDay(t *testing.T) { 174 | actual := NewUTCDateTime(2020, 1, 1, 12, 0, 0, 0).WeekDay() 175 | assert.Equal(t, actual, time.Wednesday) 176 | } 177 | 178 | func TestDateTime_IsoCalendar(t *testing.T) { 179 | year, month, day := NewUTCDateTime(2020, 12, 15, 12, 0, 0, 0).IsoCalendar() 180 | assert.Equal(t, year, 2020) 181 | assert.Equal(t, month, 12) 182 | assert.Equal(t, day, 15) 183 | } 184 | 185 | func TestDateTime_FloorYear(t *testing.T) { 186 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorYear() 187 | assert.Equal(t, NewUTCDateTime(2020, 1, 1, 0, 0, 0, 0), actual) 188 | } 189 | 190 | func TestDateTime_FloorMonth(t *testing.T) { 191 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorMonth() 192 | assert.Equal(t, NewUTCDateTime(2020, 12, 1, 0, 0, 0, 0), actual) 193 | } 194 | 195 | func TestDateTime_FloorWeek(t *testing.T) { 196 | // Weekday is already monday 197 | actual := NewUTCDateTime(2012, 12, 10, 12, 12, 49, 234).FloorWeek() 198 | assert.Equal(t, NewUTCDateTime(2012, 12, 10, 0, 0, 0, 0), actual) 199 | 200 | // Weekday is sunday 201 | actual = NewUTCDateTime(2012, 12, 16, 12, 12, 49, 234).FloorWeek() 202 | assert.Equal(t, NewUTCDateTime(2012, 12, 10, 0, 0, 0, 0), actual) 203 | 204 | // Weekday is other day 205 | actual = NewUTCDateTime(2012, 12, 12, 12, 12, 49, 234).FloorWeek() 206 | assert.Equal(t, NewUTCDateTime(2012, 12, 10, 0, 0, 0, 0), actual) 207 | } 208 | 209 | func TestDateTime_FloorDay(t *testing.T) { 210 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorDay() 211 | assert.Equal(t, NewUTCDateTime(2020, 12, 15, 0, 0, 0, 0), actual) 212 | } 213 | 214 | func TestDateTime_FloorHour(t *testing.T) { 215 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorHour() 216 | assert.Equal(t, NewUTCDateTime(2020, 12, 15, 12, 0, 0, 0), actual) 217 | } 218 | 219 | func TestDateTime_FloorMinute(t *testing.T) { 220 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorMinute() 221 | assert.Equal(t, NewUTCDateTime(2020, 12, 15, 12, 12, 0, 0), actual) 222 | } 223 | 224 | func TestDateTime_FloorSecond(t *testing.T) { 225 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).FloorSecond() 226 | assert.Equal(t, NewUTCDateTime(2020, 12, 15, 12, 12, 49, 0), actual) 227 | } 228 | 229 | func TestDateTime_CeilYear(t *testing.T) { 230 | actual := NewUTCDateTime(2020, 12, 15, 12, 12, 49, 234).CeilYear() 231 | assert.Equal(t, NewUTCDateTime(2020, 12, 31, 23, 59, 59, 999999999), actual) 232 | } 233 | 234 | func TestDateTime_CeilMonth(t *testing.T) { 235 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).CeilMonth() 236 | assert.Equal(t, NewUTCDateTime(2020, 2, 29, 23, 59, 59, 999999999), actual) 237 | } 238 | 239 | func TestDateTime_CeilWeek(t *testing.T) { 240 | actual := NewUTCDateTime(2012, 12, 16, 12, 12, 49, 234).CeilWeek() 241 | assert.Equal(t, NewUTCDateTime(2012, 12, 16, 23, 59, 59, 999999999), actual) 242 | 243 | actual = NewUTCDateTime(2012, 12, 12, 12, 12, 49, 234).CeilWeek() 244 | assert.Equal(t, NewUTCDateTime(2012, 12, 16, 23, 59, 59, 999999999), actual) 245 | } 246 | 247 | func TestDateTime_CeilDay(t *testing.T) { 248 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).CeilDay() 249 | assert.Equal(t, NewUTCDateTime(2020, 2, 15, 23, 59, 59, 999999999), actual) 250 | } 251 | 252 | func TestDateTime_CeilHour(t *testing.T) { 253 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).CeilHour() 254 | assert.Equal(t, NewUTCDateTime(2020, 2, 15, 12, 59, 59, 999999999), actual) 255 | } 256 | 257 | func TestDateTime_CeilMinute(t *testing.T) { 258 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).CeilMinute() 259 | assert.Equal(t, NewUTCDateTime(2020, 2, 15, 12, 12, 59, 999999999), actual) 260 | } 261 | 262 | func TestDateTime_CeilSecond(t *testing.T) { 263 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).CeilSecond() 264 | assert.Equal(t, NewUTCDateTime(2020, 2, 15, 12, 12, 49, 999999999), actual) 265 | } 266 | 267 | func TestDateTime_SpanYear(t *testing.T) { 268 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanYear() 269 | assert.Equal( 270 | t, 271 | NewUTCDateTime(2020, 1, 1, 0, 0, 0, 00000000), 272 | start, 273 | ) 274 | assert.Equal( 275 | t, 276 | NewUTCDateTime(2020, 12, 31, 23, 59, 59, 999999999), 277 | end, 278 | ) 279 | } 280 | 281 | func TestDateTime_SpanMonth(t *testing.T) { 282 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanMonth() 283 | assert.Equal( 284 | t, 285 | NewUTCDateTime(2020, 2, 1, 0, 0, 0, 00000000), 286 | start, 287 | ) 288 | assert.Equal( 289 | t, 290 | NewUTCDateTime(2020, 2, 29, 23, 59, 59, 999999999), 291 | end, 292 | ) 293 | } 294 | 295 | func TestDateTime_SpanDay(t *testing.T) { 296 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanDay() 297 | assert.Equal( 298 | t, 299 | NewUTCDateTime(2020, 2, 15, 0, 0, 0, 00000000), 300 | start, 301 | ) 302 | assert.Equal( 303 | t, 304 | NewUTCDateTime(2020, 2, 15, 23, 59, 59, 999999999), 305 | end, 306 | ) 307 | } 308 | 309 | func TestDateTime_SpanHour(t *testing.T) { 310 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanHour() 311 | assert.Equal( 312 | t, 313 | NewUTCDateTime(2020, 2, 15, 12, 0, 0, 00000000), 314 | start, 315 | ) 316 | assert.Equal( 317 | t, 318 | NewUTCDateTime(2020, 2, 15, 12, 59, 59, 999999999), 319 | end, 320 | ) 321 | } 322 | 323 | func TestDateTime_SpanMinute(t *testing.T) { 324 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanMinute() 325 | assert.Equal( 326 | t, 327 | NewUTCDateTime(2020, 2, 15, 12, 12, 0, 00000000), 328 | start, 329 | ) 330 | assert.Equal( 331 | t, 332 | NewUTCDateTime(2020, 2, 15, 12, 12, 59, 999999999), 333 | end, 334 | ) 335 | } 336 | 337 | func TestDateTime_SpanSecond(t *testing.T) { 338 | start, end := NewUTCDateTime(2020, 2, 15, 12, 12, 49, 234).SpanSecond() 339 | assert.Equal( 340 | t, 341 | NewUTCDateTime(2020, 2, 15, 12, 12, 49, 00000000), 342 | start, 343 | ) 344 | assert.Equal( 345 | t, 346 | NewUTCDateTime(2020, 2, 15, 12, 12, 49, 999999999), 347 | end, 348 | ) 349 | } 350 | 351 | func TestDateTime_CTimeFormat(t *testing.T) { 352 | actual := NewUTCDateTime(2020, 2, 15, 12, 12, 12, 0).CTimeFormat() 353 | assert.Equal( 354 | t, 355 | "Sat Feb 15 12:12:12 2020", 356 | actual, 357 | ) 358 | } 359 | -------------------------------------------------------------------------------- /docs/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bykof/gostradamus/5be648962cf65da5f9cac229b274f76e7b33fb1c/docs/resources/logo.png -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // FormatTokenIsNotMapped errors the given formatToken 8 | func FormatTokenIsNotMapped(formatToken string) error { 9 | return fmt.Errorf("FormatToken: %s is not mapped", formatToken) 10 | } 11 | -------------------------------------------------------------------------------- /errors_test.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "errors" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestFormatTokenIsNotMapped(t *testing.T) { 10 | actual := FormatTokenIsNotMapped("123") 11 | assert.Equal( 12 | t, 13 | errors.New("FormatToken: 123 is not mapped"), 14 | actual, 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /formats.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | const ( 4 | // Iso8601 format 5 | // 6 | // Example: 2012-12-12T12:12:12.000000 7 | // 8 | Iso8601 = "YYYY-MM-DDTHH:mm:ss.S" 9 | 10 | // Iso8601TZ format with timezone 11 | // 12 | // Example with UTC: 2012-12-12T12:12:12.000000Z 13 | // Example with timezone: 2012-12-12T12:12:12.000000+0200 14 | // 15 | Iso8601TZ = "YYYY-MM-DDTHH:mm:ss.SZ" 16 | 17 | // CTime format with ctime standard 18 | // 19 | // Example: Sat Jan 19 18:26:50 2019 20 | // 21 | CTime = "ddd MMM DD HH:mm:ss YYYY" 22 | ) 23 | -------------------------------------------------------------------------------- /formatting.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | "time" 7 | 8 | "github.com/dustin/go-humanize" 9 | ) 10 | 11 | // All FormatTokens for parsing and formatting with DateTime 12 | const ( 13 | YearFull = FormatToken("YYYY") 14 | YearShort = FormatToken("YY") 15 | 16 | MonthFull = FormatToken("MMMM") 17 | MonthAbbr = FormatToken("MMM") 18 | MonthZeroPadded = FormatToken("MM") 19 | MonthShort = FormatToken("M") 20 | 21 | DayOfYearZeroPadded = FormatToken("DDDD") 22 | DayOfMonthZeroPadded = FormatToken("DD") 23 | DayOfMonthShort = FormatToken("D") 24 | DayOfMonthOrdinal = FormatToken("Do") 25 | 26 | DayOfWeekFullName = FormatToken("dddd") 27 | DayOfWeekAbbr = FormatToken("ddd") 28 | 29 | TwentyFourHourZeroPadded = FormatToken("HH") 30 | TwelveHourZeroPadded = FormatToken("hh") 31 | TwelveHour = FormatToken("h") 32 | 33 | AMPMUpper = FormatToken("A") 34 | AMPMLower = FormatToken("a") 35 | 36 | MinuteZeroPadded = FormatToken("mm") 37 | Minute = FormatToken("m") 38 | 39 | SecondZeroPadded = FormatToken("ss") 40 | Second = FormatToken("s") 41 | MicroSecond = FormatToken("S") 42 | 43 | TimezoneFullName = FormatToken("ZZZ") 44 | TimezoneWithColon = FormatToken("zz") 45 | TimezoneWithoutColon = FormatToken("Z") 46 | 47 | GoLongMonth = goFormatToken("January") 48 | GoMonth = goFormatToken("Jan") 49 | GoNumMonth = goFormatToken("1") 50 | GoZeroMonth = goFormatToken("01") 51 | GoLongWeekDay = goFormatToken("Monday") 52 | GoWeekDay = goFormatToken("Mon") 53 | GoDay = goFormatToken("2") 54 | GoDayOrdinal = goFormatToken("Do") 55 | GoZeroDay = goFormatToken("02") 56 | GoZeroYearDay = goFormatToken("002") 57 | GoHour = goFormatToken("15") 58 | GoHour12 = goFormatToken("3") 59 | GoZeroHour12 = goFormatToken("03") 60 | GoMinute = goFormatToken("4") 61 | GoZeroMinute = goFormatToken("04") 62 | GoSecond = goFormatToken("5") 63 | GoZeroSecond = goFormatToken("05") 64 | GoLongYear = goFormatToken("2006") 65 | GoYear = goFormatToken("06") 66 | GoPM = goFormatToken("PM") 67 | Gopm = goFormatToken("pm") 68 | GoTZ = goFormatToken("MST") 69 | GoMillisecond = goFormatToken("000") 70 | GoMicrosecond = goFormatToken("000000") 71 | GoNanoSecond = goFormatToken("000000000") 72 | GoISO8601TZ = goFormatToken("Z0700") // prints Z for UTC 73 | GoISO8601SecondsTZ = goFormatToken("Z070000") 74 | GoISO8601ShortTZ = goFormatToken("Z07") 75 | GoISO8601ColonTZ = goFormatToken("Z07:00") // prints Z for UTC 76 | GoISO8601ColonSecondsTZ = goFormatToken("Z07:00:00") 77 | GoNumTZ = goFormatToken("-0700") // always numeric 78 | GoNumSecondsTz = goFormatToken("-070000") 79 | GoNumShortTZ = goFormatToken("-07") // always numeric 80 | GoNumColonTZ = goFormatToken("-07:00") // always numeric 81 | GoNumColonSecondsTZ = goFormatToken("-07:00:00") 82 | ) 83 | 84 | // FormatToken helps to hold all possible tokens for parsing and formatting 85 | type FormatToken string 86 | type formatTokens []FormatToken 87 | type goFormatToken string 88 | 89 | var ( 90 | formatTokenMap = map[FormatToken]goFormatToken{ 91 | YearFull: GoLongYear, 92 | YearShort: GoYear, 93 | MonthFull: GoLongMonth, 94 | MonthAbbr: GoMonth, 95 | MonthZeroPadded: GoZeroMonth, 96 | MonthShort: GoNumMonth, 97 | DayOfYearZeroPadded: GoZeroYearDay, 98 | DayOfMonthZeroPadded: GoZeroDay, 99 | DayOfMonthShort: GoDay, 100 | DayOfWeekFullName: GoLongWeekDay, 101 | DayOfMonthOrdinal: GoDayOrdinal, 102 | DayOfWeekAbbr: GoWeekDay, 103 | TwentyFourHourZeroPadded: GoHour, 104 | TwelveHourZeroPadded: GoZeroHour12, 105 | TwelveHour: GoHour12, 106 | AMPMUpper: GoPM, 107 | AMPMLower: Gopm, 108 | MinuteZeroPadded: GoZeroMinute, 109 | Minute: GoMinute, 110 | SecondZeroPadded: GoZeroSecond, 111 | Second: GoSecond, 112 | MicroSecond: GoMicrosecond, 113 | TimezoneFullName: GoTZ, 114 | TimezoneWithColon: GoISO8601ColonTZ, 115 | TimezoneWithoutColon: GoISO8601TZ, 116 | } 117 | 118 | allFormatTokens = formatTokens{ 119 | YearFull, 120 | YearShort, 121 | MonthFull, 122 | MonthAbbr, 123 | MonthZeroPadded, 124 | MonthShort, 125 | DayOfYearZeroPadded, 126 | DayOfMonthZeroPadded, 127 | DayOfMonthOrdinal, 128 | DayOfMonthShort, 129 | DayOfWeekFullName, 130 | DayOfWeekAbbr, 131 | TwentyFourHourZeroPadded, 132 | TwelveHourZeroPadded, 133 | TwelveHour, 134 | AMPMUpper, 135 | AMPMLower, 136 | MinuteZeroPadded, 137 | Minute, 138 | SecondZeroPadded, 139 | Second, 140 | MicroSecond, 141 | TimezoneFullName, 142 | TimezoneWithColon, 143 | TimezoneWithoutColon, 144 | } 145 | ) 146 | 147 | func (fts formatTokens) toStringSlice() []string { 148 | var stringSlice []string 149 | for _, formatToken := range fts { 150 | stringSlice = append(stringSlice, string(formatToken)) 151 | } 152 | return stringSlice 153 | } 154 | 155 | func formatTokenRegex() string { 156 | return strings.Join(allFormatTokens.toStringSlice(), "|") 157 | } 158 | 159 | // translateFormat translates all mapped formats to Go specific language 160 | func translateFormat(format string) string { 161 | re := regexp.MustCompile(formatTokenRegex()) 162 | format = string(re.ReplaceAllFunc( 163 | []byte(format), 164 | func(bytes []byte) []byte { 165 | if goFormatToken, ok := formatTokenMap[FormatToken(bytes)]; ok { 166 | return []byte(goFormatToken) 167 | } 168 | panic(FormatTokenIsNotMapped(string(bytes))) 169 | }, 170 | )) 171 | 172 | return format 173 | } 174 | 175 | // parseToTime parses the value with given format to a time.Time 176 | // error if the value could not be parsed 177 | // 178 | // parseToTime panics if the formatToken is not mapped correctly 179 | func parseToTime(value string, format string, timezone Timezone) (time.Time, error) { 180 | re := regexp.MustCompile(formatTokenRegex()) 181 | 182 | format = string(re.ReplaceAllFunc( 183 | []byte(format), 184 | func(bytes []byte) []byte { 185 | if FormatToken(bytes) == FormatToken(DayOfMonthOrdinal) { 186 | // todo: prone to accidental replacements of said matches when used incidentally outside of 'Do' context 187 | replacer := strings.NewReplacer( 188 | "th", "", 189 | "rd", "", 190 | "st", "", 191 | "nd", "", 192 | ) 193 | 194 | value = replacer.Replace(value) 195 | 196 | return []byte(DayOfMonthShort) 197 | } 198 | 199 | return bytes 200 | }, 201 | )) 202 | format = translateFormat(format) 203 | 204 | return time.ParseInLocation(format, value, timezone.Location()) 205 | } 206 | 207 | // formatFromTime formats value as time.Time with given format to a string 208 | func formatFromTime(value time.Time, format string) string { 209 | format = translateFormat(format) 210 | 211 | v := value.Format(format) 212 | 213 | v = strings.ReplaceAll(v, string(GoDayOrdinal), dayOrdinal(value)) 214 | 215 | return v 216 | } 217 | 218 | func dayOrdinal(t time.Time) string { 219 | return humanize.Ordinal(t.Day()) 220 | } 221 | -------------------------------------------------------------------------------- /formatting_test.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestParseToTime(t *testing.T) { 11 | actualResult, err := parseToTime("2019-01-01 12:12:12", "YYYY-MM-DD HH:mm:ss", UTC) 12 | assert.NoError(t, err) 13 | assert.Equal(t, time.Date(2019, 1, 1, 12, 12, 12, 0, time.UTC), actualResult) 14 | } 15 | 16 | func TestParseToTime_Error(t *testing.T) { 17 | actualResult, err := parseToTime("2019-01-01 12:12:12", "YYYY-MM-DD testHH:mm:ss", UTC) 18 | assert.Error(t, err) 19 | assert.Equal(t, time.Time{}, actualResult) 20 | } 21 | 22 | func TestParseToTimeOrdinal(t *testing.T) { 23 | actualResult, err := parseToTime("Tuesday 5th April 2011", "dddd Do MMMM YYYY", UTC) 24 | assert.NoError(t, err) 25 | assert.Equal(t, time.Date(2011, 4, 5, 0, 0, 0, 0, time.UTC), actualResult) 26 | } 27 | 28 | func TestFormatFromTime(t *testing.T) { 29 | actualResult := formatFromTime( 30 | time.Date(2011, 4, 5, 15, 7, 8, 9, time.UTC), 31 | "YYYY YY MMMM MMM MM M DDDD DD D dddd ddd HH hh h A a mm m ss s S ZZZ zz Z", 32 | ) 33 | assert.Equal( 34 | t, 35 | "2011 11 April Apr 04 4 095 05 5 Tuesday Tue 15 03 3 PM pm 07 7 08 8 000000 UTC Z Z", 36 | actualResult, 37 | ) 38 | 39 | location, err := time.LoadLocation("Japan") 40 | if err != nil { 41 | panic(err) 42 | } 43 | 44 | date := time.Date(2011, 4, 5, 15, 7, 8, 9, location) 45 | actualResult = formatFromTime( 46 | date, 47 | "ZZZ zz Z", 48 | ) 49 | 50 | assert.Equal( 51 | t, 52 | "JST +09:00 +0900", 53 | actualResult, 54 | ) 55 | } 56 | 57 | func TestOrdinal(t *testing.T) { 58 | actualResult := formatFromTime( 59 | time.Date(2011, 4, 5, 15, 7, 8, 9, time.UTC), 60 | "dddd Do MMMM YYYY", 61 | ) 62 | assert.Equal( 63 | t, 64 | "Tuesday 5th April 2011", 65 | actualResult, 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bykof/gostradamus 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/dustin/go-humanize v1.0.1 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 4 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /timezone.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import "time" 4 | 5 | // Timezone is a string type which can translate from and to time.Location 6 | type Timezone string 7 | 8 | // LoadLocation returns the time.Locatior or an error of a timezone 9 | func LoadLocation(timezone string) (*time.Location, error) { 10 | return time.LoadLocation(timezone) 11 | } 12 | 13 | // Local is a wrapper for "Local" as a Timezone 14 | func Local() Timezone { 15 | return Timezone(time.Local.String()) 16 | } 17 | 18 | // Location returns the Location of current Timezone 19 | // 20 | // Location panics if current Timzeone does not exist 21 | func (t Timezone) Location() *time.Location { 22 | location, err := LoadLocation(t.String()) 23 | if err != nil { 24 | panic(err) 25 | } 26 | return location 27 | } 28 | 29 | // String returns Timezone as string 30 | // Example: "Europe/Berlin" 31 | func (t Timezone) String() string { 32 | return string(t) 33 | } 34 | -------------------------------------------------------------------------------- /timezone_constants.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | // All possible Timezones, which are supported by Go's "time" library 4 | const ( 5 | AfricaAbidjan = Timezone("Africa/Abidjan") 6 | AfricaAccra = Timezone("Africa/Accra") 7 | AfricaAddisAbaba = Timezone("Africa/AddisAbaba") 8 | AfricaAlgiers = Timezone("Africa/Algiers") 9 | AfricaAsmara = Timezone("Africa/Asmara") 10 | AfricaBamako = Timezone("Africa/Bamako") 11 | AfricaBangui = Timezone("Africa/Bangui") 12 | AfricaBanjul = Timezone("Africa/Banjul") 13 | AfricaBissau = Timezone("Africa/Bissau") 14 | AfricaBlantyre = Timezone("Africa/Blantyre") 15 | AfricaBrazzaville = Timezone("Africa/Brazzaville") 16 | AfricaBujumbura = Timezone("Africa/Bujumbura") 17 | AfricaCairo = Timezone("Africa/Cairo") 18 | AfricaCasablanca = Timezone("Africa/Casablanca") 19 | AfricaCeuta = Timezone("Africa/Ceuta") 20 | AfricaConakry = Timezone("Africa/Conakry") 21 | AfricaDakar = Timezone("Africa/Dakar") 22 | AfricaDaresSalaam = Timezone("Africa/DaresSalaam") 23 | AfricaDjibouti = Timezone("Africa/Djibouti") 24 | AfricaDouala = Timezone("Africa/Douala") 25 | AfricaElAaiun = Timezone("Africa/ElAaiun") 26 | AfricaFreetown = Timezone("Africa/Freetown") 27 | AfricaGaborone = Timezone("Africa/Gaborone") 28 | AfricaHarare = Timezone("Africa/Harare") 29 | AfricaJohannesburg = Timezone("Africa/Johannesburg") 30 | AfricaJuba = Timezone("Africa/Juba") 31 | AfricaKampala = Timezone("Africa/Kampala") 32 | AfricaKhartoum = Timezone("Africa/Khartoum") 33 | AfricaKigali = Timezone("Africa/Kigali") 34 | AfricaKinshasa = Timezone("Africa/Kinshasa") 35 | AfricaLagos = Timezone("Africa/Lagos") 36 | AfricaLibreville = Timezone("Africa/Libreville") 37 | AfricaLome = Timezone("Africa/Lome") 38 | AfricaLuanda = Timezone("Africa/Luanda") 39 | AfricaLubumbashi = Timezone("Africa/Lubumbashi") 40 | AfricaLusaka = Timezone("Africa/Lusaka") 41 | AfricaMalabo = Timezone("Africa/Malabo") 42 | AfricaMaputo = Timezone("Africa/Maputo") 43 | AfricaMaseru = Timezone("Africa/Maseru") 44 | AfricaMbabane = Timezone("Africa/Mbabane") 45 | AfricaMogadishu = Timezone("Africa/Mogadishu") 46 | AfricaMonrovia = Timezone("Africa/Monrovia") 47 | AfricaNairobi = Timezone("Africa/Nairobi") 48 | AfricaNdjamena = Timezone("Africa/Ndjamena") 49 | AfricaNiamey = Timezone("Africa/Niamey") 50 | AfricaNouakchott = Timezone("Africa/Nouakchott") 51 | AfricaOuagadougou = Timezone("Africa/Ouagadougou") 52 | AfricaPortoNovo = Timezone("Africa/Porto-Novo") 53 | AfricaSaoTome = Timezone("Africa/SaoTome") 54 | AfricaTripoli = Timezone("Africa/Tripoli") 55 | AfricaTunis = Timezone("Africa/Tunis") 56 | AfricaWindhoek = Timezone("Africa/Windhoek") 57 | AmericaAdak = Timezone("America/Adak") 58 | AmericaAnchorage = Timezone("America/Anchorage") 59 | AmericaAnguilla = Timezone("America/Anguilla") 60 | AmericaAntigua = Timezone("America/Antigua") 61 | AmericaAraguaina = Timezone("America/Araguaina") 62 | AmericaArgentinaBuenosAires = Timezone("America/Argentina/BuenosAires") 63 | AmericaArgentinaCatamarca = Timezone("America/Argentina/Catamarca") 64 | AmericaArgentinaComodRivadavia = Timezone("America/Argentina/ComodRivadavia") 65 | AmericaArgentinaCordoba = Timezone("America/Argentina/Cordoba") 66 | AmericaArgentinaJujuy = Timezone("America/Argentina/Jujuy Jujuy") 67 | AmericaArgentinaLaRioja = Timezone("America/Argentina/LaRioja") 68 | AmericaArgentinaMendoza = Timezone("America/Argentina/Mendoza") 69 | AmericaArgentinaRioGallegos = Timezone("America/Argentina/RioGallegos") 70 | AmericaArgentinaSalta = Timezone("America/Argentina/Salta Salta") 71 | AmericaArgentinaSanJuan = Timezone("America/Argentina/SanJuan") 72 | AmericaArgentinaSanLuis = Timezone("America/Argentina/SanLuis") 73 | AmericaArgentinaTucuman = Timezone("America/Argentina/Tucuman") 74 | AmericaArgentinaUshuaia = Timezone("America/Argentina/Ushuaia") 75 | AmericaAruba = Timezone("America/Aruba") 76 | AmericaAsuncion = Timezone("America/Asuncion") 77 | AmericaAtikokan = Timezone("America/Atikokan") 78 | AmericaAtka = Timezone("America/Atka") 79 | AmericaBahia = Timezone("America/Bahia") 80 | AmericaBahiaBanderas = Timezone("America/BahiaBanderas") 81 | AmericaBarbados = Timezone("America/Barbados") 82 | AmericaBelem = Timezone("America/Belem") 83 | AmericaBelize = Timezone("America/Belize") 84 | AmericaBlanc = Timezone("America/Blanc") 85 | AmericaBoaVista = Timezone("America/BoaVista") 86 | AmericaBogota = Timezone("America/Bogota") 87 | AmericaBoise = Timezone("America/Boise") 88 | AmericaBuenosAires = Timezone("America/BuenosAires") 89 | AmericaCambridgeBay = Timezone("America/CambridgeBay") 90 | AmericaCampoGrande = Timezone("America/CampoGrande") 91 | AmericaCancun = Timezone("America/Cancun") 92 | AmericaCaracas = Timezone("America/Caracas") 93 | AmericaCatamarca = Timezone("America/Catamarca") 94 | AmericaCayenne = Timezone("America/Cayenne") 95 | AmericaCayman = Timezone("America/Cayman") 96 | AmericaChicago = Timezone("America/Chicago") 97 | AmericaChihuahua = Timezone("America/Chihuahua") 98 | AmericaCoralHarbour = Timezone("America/CoralHarbour") 99 | AmericaCordoba = Timezone("America/Cordoba") 100 | AmericaCostaRica = Timezone("America/CostaRica") 101 | AmericaCreston = Timezone("America/Creston") 102 | AmericaCuiaba = Timezone("America/Cuiaba") 103 | AmericaCuracao = Timezone("America/Curacao") 104 | AmericaDanmarkshavn = Timezone("America/Danmarkshavn") 105 | AmericaDawson = Timezone("America/Dawson") 106 | AmericaDawsonCreek = Timezone("America/DawsonCreek") 107 | AmericaDenver = Timezone("America/Denver") 108 | AmericaDetroit = Timezone("America/Detroit") 109 | AmericaDominica = Timezone("America/Dominica") 110 | AmericaEdmonton = Timezone("America/Edmonton") 111 | AmericaEirunepe = Timezone("America/Eirunepe") 112 | AmericaElSalvador = Timezone("America/ElSalvador") 113 | AmericaEnsenada = Timezone("America/Ensenada") 114 | AmericaFortNelson = Timezone("America/FortNelson") 115 | AmericaFortWayne = Timezone("America/FortWayne") 116 | AmericaFortaleza = Timezone("America/Fortaleza") 117 | AmericaGlaceBay = Timezone("America/GlaceBay") 118 | AmericaGodthab = Timezone("America/Godthab") 119 | AmericaGooseBay = Timezone("America/GooseBay") 120 | AmericaGrandTurk = Timezone("America/GrandTurk") 121 | AmericaGrenada = Timezone("America/Grenada") 122 | AmericaGuadeloupe = Timezone("America/Guadeloupe") 123 | AmericaGuatemala = Timezone("America/Guatemala") 124 | AmericaGuayaquil = Timezone("America/Guayaquil") 125 | AmericaGuyana = Timezone("America/Guyana") 126 | AmericaHalifax = Timezone("America/Halifax") 127 | AmericaHavana = Timezone("America/Havana") 128 | AmericaHermosillo = Timezone("America/Hermosillo") 129 | AmericaIndianaIndianapolis = Timezone("America/Indiana/Indianapolis") 130 | AmericaIndianaKnox = Timezone("America/Indiana/Knox") 131 | AmericaIndianaMarengo = Timezone("America/Indiana/Marengo") 132 | AmericaIndianaPetersburg = Timezone("America/Indiana/Petersburg") 133 | AmericaIndianaTellCity = Timezone("America/Indiana/TellCity") 134 | AmericaIndianaVevay = Timezone("America/Indiana/Vevay") 135 | AmericaIndianaVincennes = Timezone("America/Indiana/Vincennes") 136 | AmericaIndianaWinamac = Timezone("America/Indiana/Winamac") 137 | AmericaIndianapolis = Timezone("America/Indianapolis") 138 | AmericaInuvik = Timezone("America/Inuvik") 139 | AmericaIqaluit = Timezone("America/Iqaluit") 140 | AmericaJamaica = Timezone("America/Jamaica") 141 | AmericaJujuy = Timezone("America/Jujuy") 142 | AmericaJuneau = Timezone("America/Juneau") 143 | AmericaKentuckyLouisville = Timezone("America/Kentucky/Louisville") 144 | AmericaKentuckyMonticello = Timezone("America/Kentucky/Monticello") 145 | AmericaKnoxIN = Timezone("America/KnoxIN") 146 | AmericaKralendijk = Timezone("America/Kralendijk") 147 | AmericaLaPaz = Timezone("America/LaPaz") 148 | AmericaLima = Timezone("America/Lima") 149 | AmericaLosAngeles = Timezone("America/LosAngeles") 150 | AmericaLouisville = Timezone("America/Louisville") 151 | AmericaLowerPrinces = Timezone("America/LowerPrinces") 152 | AmericaMaceio = Timezone("America/Maceio") 153 | AmericaManagua = Timezone("America/Managua") 154 | AmericaManaus = Timezone("America/Manaus") 155 | AmericaMarigot = Timezone("America/Marigot") 156 | AmericaMartinique = Timezone("America/Martinique") 157 | AmericaMatamoros = Timezone("America/Matamoros") 158 | AmericaMazatlan = Timezone("America/Mazatlan") 159 | AmericaMendoza = Timezone("America/Mendoza") 160 | AmericaMenominee = Timezone("America/Menominee") 161 | AmericaMerida = Timezone("America/Merida") 162 | AmericaMetlakatla = Timezone("America/Metlakatla") 163 | AmericaMexicoCity = Timezone("America/MexicoCity") 164 | AmericaMiquelon = Timezone("America/Miquelon") 165 | AmericaMoncton = Timezone("America/Moncton") 166 | AmericaMonterrey = Timezone("America/Monterrey") 167 | AmericaMontevideo = Timezone("America/Montevideo") 168 | AmericaMontreal = Timezone("America/Montreal") 169 | AmericaMontserrat = Timezone("America/Montserrat") 170 | AmericaNassau = Timezone("America/Nassau") 171 | AmericaNewYork = Timezone("America/NewYork") 172 | AmericaNipigon = Timezone("America/Nipigon") 173 | AmericaNome = Timezone("America/Nome") 174 | AmericaNoronha = Timezone("America/Noronha") 175 | AmericaNorthDakotaBeulah = Timezone("America/NorthDakota/Beulah") 176 | AmericaNorthDakotaCenter = Timezone("America/NorthDakota/Center") 177 | AmericaNorthDakotaNewSalem = Timezone("America/NorthDakota/NewSalem") 178 | AmericaOjinaga = Timezone("America/Ojinaga") 179 | AmericaPanama = Timezone("America/Panama") 180 | AmericaPangnirtung = Timezone("America/Pangnirtung") 181 | AmericaParamaribo = Timezone("America/Paramaribo") 182 | AmericaPhoenix = Timezone("America/Phoenix") 183 | AmericaPortofSpain = Timezone("America/PortofSpain") 184 | AmericaPort = Timezone("America/Port") 185 | AmericaPortoAcre = Timezone("America/PortoAcre") 186 | AmericaPortoVelho = Timezone("America/PortoVelho") 187 | AmericaPuertoRico = Timezone("America/PuertoRico") 188 | AmericaPuntaArenas = Timezone("America/PuntaArenas") 189 | AmericaRainyRiver = Timezone("America/RainyRiver") 190 | AmericaRankinInlet = Timezone("America/RankinInlet") 191 | AmericaRecife = Timezone("America/Recife") 192 | AmericaRegina = Timezone("America/Regina") 193 | AmericaResolute = Timezone("America/Resolute") 194 | AmericaRioBranco = Timezone("America/RioBranco") 195 | AmericaRosario = Timezone("America/Rosario") 196 | AmericaSantaIsabel = Timezone("America/SantaIsabel") 197 | AmericaSantarem = Timezone("America/Santarem") 198 | AmericaSantiago = Timezone("America/Santiago") 199 | AmericaSantoDomingo = Timezone("America/SantoDomingo") 200 | AmericaSaoPaulo = Timezone("America/SaoPaulo") 201 | AmericaScoresbysund = Timezone("America/Scoresbysund") 202 | AmericaShiprock = Timezone("America/Shiprock") 203 | AmericaSitka = Timezone("America/Sitka") 204 | AmericaStBarthelemy = Timezone("America/StBarthelemy") 205 | AmericaStJohns = Timezone("America/StJohns") 206 | AmericaStKitts = Timezone("America/StKitts") 207 | AmericaStLucia = Timezone("America/StLucia") 208 | AmericaStThomas = Timezone("America/StThomas") 209 | AmericaStVincent = Timezone("America/StVincent") 210 | AmericaSwiftCurrent = Timezone("America/SwiftCurrent") 211 | AmericaTegucigalpa = Timezone("America/Tegucigalpa") 212 | AmericaThule = Timezone("America/Thule") 213 | AmericaThunderBay = Timezone("America/ThunderBay") 214 | AmericaTijuana = Timezone("America/Tijuana") 215 | AmericaToronto = Timezone("America/Toronto") 216 | AmericaTortola = Timezone("America/Tortola") 217 | AmericaVancouver = Timezone("America/Vancouver") 218 | AmericaVirgin = Timezone("America/Virgin") 219 | AmericaWhitehorse = Timezone("America/Whitehorse") 220 | AmericaWinnipeg = Timezone("America/Winnipeg") 221 | AmericaYakutat = Timezone("America/Yakutat") 222 | AmericaYellowknife = Timezone("America/Yellowknife") 223 | AntarcticaCasey = Timezone("Antarctica/Casey") 224 | AntarcticaDavis = Timezone("Antarctica/Davis") 225 | AntarcticaDumontDUrville = Timezone("Antarctica/DumontDUrville") 226 | AntarcticaMacquarie = Timezone("Antarctica/Macquarie") 227 | AntarcticaMawson = Timezone("Antarctica/Mawson") 228 | AntarcticaMcMurdo = Timezone("Antarctica/McMurdo") 229 | AntarcticaPalmer = Timezone("Antarctica/Palmer") 230 | AntarcticaRothera = Timezone("Antarctica/Rothera") 231 | AntarcticaSouthPole = Timezone("Antarctica/SouthPole") 232 | AntarcticaSyowa = Timezone("Antarctica/Syowa") 233 | AntarcticaTroll = Timezone("Antarctica/Troll") 234 | AntarcticaVostok = Timezone("Antarctica/Vostok") 235 | ArcticLongyearbyen = Timezone("Arctic/Longyearbyen") 236 | AsiaAden = Timezone("Asia/Aden") 237 | AsiaAlmaty = Timezone("Asia/Almaty") 238 | AsiaAmman = Timezone("Asia/Amman") 239 | AsiaAnadyr = Timezone("Asia/Anadyr") 240 | AsiaAqtau = Timezone("Asia/Aqtau") 241 | AsiaAqtobe = Timezone("Asia/Aqtobe") 242 | AsiaAshgabat = Timezone("Asia/Ashgabat") 243 | AsiaAshkhabad = Timezone("Asia/Ashkhabad") 244 | AsiaAtyrau = Timezone("Asia/Atyrau") 245 | AsiaBaghdad = Timezone("Asia/Baghdad") 246 | AsiaBahrain = Timezone("Asia/Bahrain") 247 | AsiaBaku = Timezone("Asia/Baku") 248 | AsiaBangkok = Timezone("Asia/Bangkok") 249 | AsiaBarnaul = Timezone("Asia/Barnaul") 250 | AsiaBeirut = Timezone("Asia/Beirut") 251 | AsiaBishkek = Timezone("Asia/Bishkek") 252 | AsiaBrunei = Timezone("Asia/Brunei") 253 | AsiaCalcutta = Timezone("Asia/Calcutta") 254 | AsiaChita = Timezone("Asia/Chita") 255 | AsiaChoibalsan = Timezone("Asia/Choibalsan") 256 | AsiaChongqing = Timezone("Asia/Chongqing") 257 | AsiaChungking = Timezone("Asia/Chungking") 258 | AsiaColombo = Timezone("Asia/Colombo") 259 | AsiaDacca = Timezone("Asia/Dacca") 260 | AsiaDamascus = Timezone("Asia/Damascus") 261 | AsiaDhaka = Timezone("Asia/Dhaka") 262 | AsiaDili = Timezone("Asia/Dili") 263 | AsiaDubai = Timezone("Asia/Dubai") 264 | AsiaDushanbe = Timezone("Asia/Dushanbe") 265 | AsiaFamagusta = Timezone("Asia/Famagusta") 266 | AsiaGaza = Timezone("Asia/Gaza") 267 | AsiaHarbin = Timezone("Asia/Harbin") 268 | AsiaHebron = Timezone("Asia/Hebron") 269 | AsiaHoChiMinh = Timezone("Asia/HoChiMinh") 270 | AsiaHongKong = Timezone("Asia/HongKong") 271 | AsiaHovd = Timezone("Asia/Hovd") 272 | AsiaIrkutsk = Timezone("Asia/Irkutsk") 273 | AsiaIstanbul = Timezone("Asia/Istanbul") 274 | AsiaJakarta = Timezone("Asia/Jakarta") 275 | AsiaJayapura = Timezone("Asia/Jayapura") 276 | AsiaJerusalem = Timezone("Asia/Jerusalem") 277 | AsiaKabul = Timezone("Asia/Kabul") 278 | AsiaKamchatka = Timezone("Asia/Kamchatka") 279 | AsiaKarachi = Timezone("Asia/Karachi") 280 | AsiaKashgar = Timezone("Asia/Kashgar") 281 | AsiaKathmandu = Timezone("Asia/Kathmandu") 282 | AsiaKatmandu = Timezone("Asia/Katmandu") 283 | AsiaKhandyga = Timezone("Asia/Khandyga") 284 | AsiaKolkata = Timezone("Asia/Kolkata") 285 | AsiaKrasnoyarsk = Timezone("Asia/Krasnoyarsk") 286 | AsiaKualaLumpur = Timezone("Asia/KualaLumpur") 287 | AsiaKuching = Timezone("Asia/Kuching") 288 | AsiaKuwait = Timezone("Asia/Kuwait") 289 | AsiaMacao = Timezone("Asia/Macao") 290 | AsiaMacau = Timezone("Asia/Macau") 291 | AsiaMagadan = Timezone("Asia/Magadan") 292 | AsiaMakassar = Timezone("Asia/Makassar") 293 | AsiaManila = Timezone("Asia/Manila") 294 | AsiaMuscat = Timezone("Asia/Muscat") 295 | AsiaNovokuznetsk = Timezone("Asia/Novokuznetsk") 296 | AsiaNovosibirsk = Timezone("Asia/Novosibirsk") 297 | AsiaOmsk = Timezone("Asia/Omsk") 298 | AsiaOral = Timezone("Asia/Oral") 299 | AsiaPhnomPenh = Timezone("Asia/PhnomPenh") 300 | AsiaPontianak = Timezone("Asia/Pontianak") 301 | AsiaPyongyang = Timezone("Asia/Pyongyang") 302 | AsiaQatar = Timezone("Asia/Qatar") 303 | AsiaQyzylorda = Timezone("Asia/Qyzylorda") 304 | AsiaRangoon = Timezone("Asia/Rangoon") 305 | AsiaRiyadh = Timezone("Asia/Riyadh") 306 | AsiaSaigon = Timezone("Asia/Saigon") 307 | AsiaSakhalin = Timezone("Asia/Sakhalin") 308 | AsiaSamarkand = Timezone("Asia/Samarkand") 309 | AsiaSeoul = Timezone("Asia/Seoul") 310 | AsiaShanghai = Timezone("Asia/Shanghai") 311 | AsiaSingapore = Timezone("Asia/Singapore") 312 | AsiaSrednekolymsk = Timezone("Asia/Srednekolymsk") 313 | AsiaTaipei = Timezone("Asia/Taipei") 314 | AsiaTashkent = Timezone("Asia/Tashkent") 315 | AsiaTbilisi = Timezone("Asia/Tbilisi") 316 | AsiaTehran = Timezone("Asia/Tehran") 317 | AsiaTelAviv = Timezone("Asia/TelAviv") 318 | AsiaThimbu = Timezone("Asia/Thimbu") 319 | AsiaThimphu = Timezone("Asia/Thimphu") 320 | AsiaTokyo = Timezone("Asia/Tokyo") 321 | AsiaTomsk = Timezone("Asia/Tomsk") 322 | AsiaUjungPandang = Timezone("Asia/UjungPandang") 323 | AsiaUlaanbaatar = Timezone("Asia/Ulaanbaatar") 324 | AsiaUlanBator = Timezone("Asia/UlanBator") 325 | AsiaUrumqi = Timezone("Asia/Urumqi") 326 | AsiaUst = Timezone("Asia/Ust") 327 | AsiaVientiane = Timezone("Asia/Vientiane") 328 | AsiaVladivostok = Timezone("Asia/Vladivostok") 329 | AsiaYakutsk = Timezone("Asia/Yakutsk") 330 | AsiaYangon = Timezone("Asia/Yangon") 331 | AsiaYekaterinburg = Timezone("Asia/Yekaterinburg") 332 | AsiaYerevan = Timezone("Asia/Yerevan") 333 | AtlanticAzores = Timezone("Atlantic/Azores") 334 | AtlanticBermuda = Timezone("Atlantic/Bermuda") 335 | AtlanticCanary = Timezone("Atlantic/Canary") 336 | AtlanticCapeVerde = Timezone("Atlantic/CapeVerde") 337 | AtlanticFaeroe = Timezone("Atlantic/Faeroe") 338 | AtlanticFaroe = Timezone("Atlantic/Faroe") 339 | AtlanticJanMayen = Timezone("Atlantic/JanMayen") 340 | AtlanticMadeira = Timezone("Atlantic/Madeira") 341 | AtlanticReykjavik = Timezone("Atlantic/Reykjavik") 342 | AtlanticSouthGeorgia = Timezone("Atlantic/SouthGeorgia") 343 | AtlanticStHelena = Timezone("Atlantic/StHelena") 344 | AtlanticStanley = Timezone("Atlantic/Stanley") 345 | AustraliaACT = Timezone("Australia/ACT") 346 | AustraliaAdelaide = Timezone("Australia/Adelaide") 347 | AustraliaBrisbane = Timezone("Australia/Brisbane") 348 | AustraliaBrokenHill = Timezone("Australia/BrokenHill") 349 | AustraliaCanberra = Timezone("Australia/Canberra") 350 | AustraliaCurrie = Timezone("Australia/Currie") 351 | AustraliaDarwin = Timezone("Australia/Darwin") 352 | AustraliaEucla = Timezone("Australia/Eucla") 353 | AustraliaHobart = Timezone("Australia/Hobart") 354 | AustraliaLHI = Timezone("Australia/LHI") 355 | AustraliaLindeman = Timezone("Australia/Lindeman") 356 | AustraliaLordHowe = Timezone("Australia/LordHowe") 357 | AustraliaMelbourne = Timezone("Australia/Melbourne") 358 | AustraliaNorth = Timezone("Australia/North") 359 | AustraliaNSW = Timezone("Australia/NSW") 360 | AustraliaPerth = Timezone("Australia/Perth") 361 | AustraliaQueensland = Timezone("Australia/Queensland") 362 | AustraliaSouth = Timezone("Australia/South") 363 | AustraliaSydney = Timezone("Australia/Sydney") 364 | AustraliaTasmania = Timezone("Australia/Tasmania") 365 | AustraliaVictoria = Timezone("Australia/Victoria") 366 | AustraliaWest = Timezone("Australia/West") 367 | AustraliaYancowinna = Timezone("Australia/Yancowinna") 368 | BrazilAcre = Timezone("Brazil/Acre") 369 | BrazilDeNoronha = Timezone("Brazil/DeNoronha") 370 | BrazilEast = Timezone("Brazil/East") 371 | BrazilWest = Timezone("Brazil/West") 372 | CanadaAtlantic = Timezone("Canada/Atlantic") 373 | CanadaCentral = Timezone("Canada/Central") 374 | CanadaEastern = Timezone("Canada/Eastern") 375 | CanadaMountain = Timezone("Canada/Mountain") 376 | CanadaNewfoundland = Timezone("Canada/Newfoundland") 377 | CanadaPacific = Timezone("Canada/Pacific") 378 | CanadaSaskatchewan = Timezone("Canada/Saskatchewan") 379 | CanadaYukon = Timezone("Canada/Yukon") 380 | CET = Timezone("CET") 381 | ChileContinental = Timezone("Chile/Continental") 382 | ChileEasterIsland = Timezone("Chile/EasterIsland") 383 | CST6CDT = Timezone("CST6CDT") 384 | Cuba = Timezone("Cuba") 385 | EET = Timezone("EET") 386 | Egypt = Timezone("Egypt") 387 | Eire = Timezone("Eire") 388 | EST = Timezone("EST") 389 | EST5EDT = Timezone("EST5EDT") 390 | EtcGMT = Timezone("Etc/GMT") 391 | EtcGMTPlus0 = Timezone("Etc/GMT+0") 392 | EtcGMTPlus1 = Timezone("Etc/GMT+1") 393 | EtcGMTPlus10 = Timezone("Etc/GMT+10") 394 | EtcGMTPlus11 = Timezone("Etc/GMT+11") 395 | EtcGMTPlus12 = Timezone("Etc/GMT+12") 396 | EtcGMTPlus2 = Timezone("Etc/GMT+2") 397 | EtcGMTPlus3 = Timezone("Etc/GMT+3") 398 | EtcGMTPlus4 = Timezone("Etc/GMT+4") 399 | EtcGMTPlus5 = Timezone("Etc/GMT+5") 400 | EtcGMTPlus6 = Timezone("Etc/GMT+6") 401 | EtcGMTPlus7 = Timezone("Etc/GMT+7") 402 | EtcGMTPlus8 = Timezone("Etc/GMT+8") 403 | EtcGMTPlus9 = Timezone("Etc/GMT+9") 404 | EtcGMT0 = Timezone("Etc/GMT0") 405 | EtcGMTMinus0 = Timezone("Etc/GMT-0") 406 | EtcGMTMinus1 = Timezone("Etc/GMT-1") 407 | EtcGMTMinus10 = Timezone("Etc/GMT-10") 408 | EtcGMTMinus11 = Timezone("Etc/GMT-11") 409 | EtcGMTMinus12 = Timezone("Etc/GMT-12") 410 | EtcGMTMinus13 = Timezone("Etc/GMT-13") 411 | EtcGMTMinus14 = Timezone("Etc/GMT-14") 412 | EtcGMTMinus2 = Timezone("Etc/GMT-2") 413 | EtcGMTMinus3 = Timezone("Etc/GMT-3") 414 | EtcGMTMinus4 = Timezone("Etc/GMT-4") 415 | EtcGMTMinus5 = Timezone("Etc/GMT-5") 416 | EtcGMTMinus6 = Timezone("Etc/GMT-6") 417 | EtcGMTMinus7 = Timezone("Etc/GMT-7") 418 | EtcGMTMinus8 = Timezone("Etc/GMT-8") 419 | EtcGMTMinus9 = Timezone("Etc/GMT-9") 420 | EtcGreenwich = Timezone("Etc/Greenwich") 421 | EtcUCT = Timezone("Etc/UCT") 422 | EtcUniversal = Timezone("Etc/Universal") 423 | EtcUTC = Timezone("Etc/UTC") 424 | EtcZulu = Timezone("Etc/Zulu") 425 | EuropeAmsterdam = Timezone("Europe/Amsterdam") 426 | EuropeAndorra = Timezone("Europe/Andorra") 427 | EuropeAstrakhan = Timezone("Europe/Astrakhan") 428 | EuropeAthens = Timezone("Europe/Athens") 429 | EuropeBelfast = Timezone("Europe/Belfast") 430 | EuropeBelgrade = Timezone("Europe/Belgrade") 431 | EuropeBerlin = Timezone("Europe/Berlin") 432 | EuropeBratislava = Timezone("Europe/Bratislava") 433 | EuropeBrussels = Timezone("Europe/Brussels") 434 | EuropeBucharest = Timezone("Europe/Bucharest") 435 | EuropeBudapest = Timezone("Europe/Budapest") 436 | EuropeBusingen = Timezone("Europe/Busingen") 437 | EuropeChisinau = Timezone("Europe/Chisinau") 438 | EuropeCopenhagen = Timezone("Europe/Copenhagen") 439 | EuropeDublin = Timezone("Europe/Dublin") 440 | EuropeGibraltar = Timezone("Europe/Gibraltar") 441 | EuropeGuernsey = Timezone("Europe/Guernsey") 442 | EuropeHelsinki = Timezone("Europe/Helsinki") 443 | EuropeIsleofMan = Timezone("Europe/IsleofMan") 444 | EuropeIstanbul = Timezone("Europe/Istanbul") 445 | EuropeJersey = Timezone("Europe/Jersey") 446 | EuropeKaliningrad = Timezone("Europe/Kaliningrad") 447 | EuropeKiev = Timezone("Europe/Kiev") 448 | EuropeKirov = Timezone("Europe/Kirov") 449 | EuropeLisbon = Timezone("Europe/Lisbon") 450 | EuropeLjubljana = Timezone("Europe/Ljubljana") 451 | EuropeLondon = Timezone("Europe/London") 452 | EuropeLuxembourg = Timezone("Europe/Luxembourg") 453 | EuropeMadrid = Timezone("Europe/Madrid") 454 | EuropeMalta = Timezone("Europe/Malta") 455 | EuropeMariehamn = Timezone("Europe/Mariehamn") 456 | EuropeMinsk = Timezone("Europe/Minsk") 457 | EuropeMonaco = Timezone("Europe/Monaco") 458 | EuropeMoscow = Timezone("Europe/Moscow") 459 | AsiaNicosia = Timezone("Asia/Nicosia") 460 | EuropeOslo = Timezone("Europe/Oslo") 461 | EuropeParis = Timezone("Europe/Paris") 462 | EuropePodgorica = Timezone("Europe/Podgorica") 463 | EuropePrague = Timezone("Europe/Prague") 464 | EuropeRiga = Timezone("Europe/Riga") 465 | EuropeRome = Timezone("Europe/Rome") 466 | EuropeSamara = Timezone("Europe/Samara") 467 | EuropeSanMarino = Timezone("Europe/SanMarino") 468 | EuropeSarajevo = Timezone("Europe/Sarajevo") 469 | EuropeSaratov = Timezone("Europe/Saratov") 470 | EuropeSimferopol = Timezone("Europe/Simferopol") 471 | EuropeSkopje = Timezone("Europe/Skopje") 472 | EuropeSofia = Timezone("Europe/Sofia") 473 | EuropeStockholm = Timezone("Europe/Stockholm") 474 | EuropeTallinn = Timezone("Europe/Tallinn") 475 | EuropeTirane = Timezone("Europe/Tirane") 476 | EuropeTiraspol = Timezone("Europe/Tiraspol") 477 | EuropeUlyanovsk = Timezone("Europe/Ulyanovsk") 478 | EuropeUzhgorod = Timezone("Europe/Uzhgorod") 479 | EuropeVaduz = Timezone("Europe/Vaduz") 480 | EuropeVatican = Timezone("Europe/Vatican") 481 | EuropeVienna = Timezone("Europe/Vienna") 482 | EuropeVilnius = Timezone("Europe/Vilnius") 483 | EuropeVolgograd = Timezone("Europe/Volgograd") 484 | EuropeWarsaw = Timezone("Europe/Warsaw") 485 | EuropeZagreb = Timezone("Europe/Zagreb") 486 | EuropeZaporozhye = Timezone("Europe/Zaporozhye") 487 | EuropeZurich = Timezone("Europe/Zurich") 488 | GB = Timezone("GB") 489 | GBEire = Timezone("GB-Eire") 490 | GMT = Timezone("GMT") 491 | GMTPlus0 = Timezone("GMT+0") 492 | GMT0 = Timezone("GMT0") 493 | GMTMinus0 = Timezone("GMT-0") 494 | Greenwich = Timezone("Greenwich") 495 | Hongkong = Timezone("Hongkong") 496 | HST = Timezone("HST") 497 | Iceland = Timezone("Iceland") 498 | IndianAntananarivo = Timezone("Indian/Antananarivo") 499 | IndianChagos = Timezone("Indian/Chagos") 500 | IndianChristmas = Timezone("Indian/Christmas") 501 | IndianCocos = Timezone("Indian/Cocos") 502 | IndianComoro = Timezone("Indian/Comoro") 503 | IndianKerguelen = Timezone("Indian/Kerguelen") 504 | IndianMahe = Timezone("Indian/Mahe") 505 | IndianMaldives = Timezone("Indian/Maldives") 506 | IndianMauritius = Timezone("Indian/Mauritius") 507 | IndianMayotte = Timezone("Indian/Mayotte") 508 | IndianReunion = Timezone("Indian/Reunion") 509 | Iran = Timezone("Iran") 510 | Israel = Timezone("Israel") 511 | Jamaica = Timezone("Jamaica") 512 | Japan = Timezone("Japan") 513 | Kwajalein = Timezone("Kwajalein") 514 | Libya = Timezone("Libya") 515 | MET = Timezone("MET") 516 | MexicoBajaNorte = Timezone("Mexico/BajaNorte") 517 | MexicoBajaSur = Timezone("Mexico/BajaSur") 518 | MexicoGeneral = Timezone("Mexico/General") 519 | MST = Timezone("MST") 520 | MST7MDT = Timezone("MST7MDT") 521 | Navajo = Timezone("Navajo") 522 | NZ = Timezone("NZ") 523 | NZCHAT = Timezone("NZ-CHAT") 524 | PacificApia = Timezone("Pacific/Apia") 525 | PacificAuckland = Timezone("Pacific/Auckland") 526 | PacificBougainville = Timezone("Pacific/Bougainville") 527 | PacificChatham = Timezone("Pacific/Chatham") 528 | PacificChuuk = Timezone("Pacific/Chuuk") 529 | PacificEaster = Timezone("Pacific/Easter") 530 | PacificEfate = Timezone("Pacific/Efate") 531 | PacificEnderbury = Timezone("Pacific/Enderbury") 532 | PacificFakaofo = Timezone("Pacific/Fakaofo") 533 | PacificFiji = Timezone("Pacific/Fiji") 534 | PacificFunafuti = Timezone("Pacific/Funafuti") 535 | PacificGalapagos = Timezone("Pacific/Galapagos") 536 | PacificGambier = Timezone("Pacific/Gambier") 537 | PacificGuadalcanal = Timezone("Pacific/Guadalcanal") 538 | PacificGuam = Timezone("Pacific/Guam") 539 | PacificHonolulu = Timezone("Pacific/Honolulu") 540 | PacificJohnston = Timezone("Pacific/Johnston") 541 | PacificKiritimati = Timezone("Pacific/Kiritimati") 542 | PacificKosrae = Timezone("Pacific/Kosrae") 543 | PacificKwajalein = Timezone("Pacific/Kwajalein") 544 | PacificMajuro = Timezone("Pacific/Majuro") 545 | PacificMarquesas = Timezone("Pacific/Marquesas") 546 | PacificMidway = Timezone("Pacific/Midway") 547 | PacificNauru = Timezone("Pacific/Nauru") 548 | PacificNiue = Timezone("Pacific/Niue") 549 | PacificNorfolk = Timezone("Pacific/Norfolk") 550 | PacificNoumea = Timezone("Pacific/Noumea") 551 | PacificPagoPago = Timezone("Pacific/PagoPago") 552 | PacificPalau = Timezone("Pacific/Palau") 553 | PacificPitcairn = Timezone("Pacific/Pitcairn") 554 | PacificPohnpei = Timezone("Pacific/Pohnpei") 555 | PacificPonape = Timezone("Pacific/Ponape") 556 | PacificPortMoresby = Timezone("Pacific/PortMoresby") 557 | PacificRarotonga = Timezone("Pacific/Rarotonga") 558 | PacificSaipan = Timezone("Pacific/Saipan") 559 | PacificSamoa = Timezone("Pacific/Samoa") 560 | PacificTahiti = Timezone("Pacific/Tahiti") 561 | PacificTarawa = Timezone("Pacific/Tarawa") 562 | PacificTongatapu = Timezone("Pacific/Tongatapu") 563 | PacificTruk = Timezone("Pacific/Truk") 564 | PacificWake = Timezone("Pacific/Wake") 565 | PacificWallis = Timezone("Pacific/Wallis") 566 | PacificYap = Timezone("Pacific/Yap") 567 | Poland = Timezone("Poland") 568 | Portugal = Timezone("Portugal") 569 | PRC = Timezone("PRC") 570 | PST8PDT = Timezone("PST8PDT") 571 | ROC = Timezone("ROC") 572 | ROK = Timezone("ROK") 573 | Singapore = Timezone("Singapore") 574 | Turkey = Timezone("Turkey") 575 | UCT = Timezone("UCT") 576 | Universal = Timezone("Universal") 577 | USAlaska = Timezone("US/Alaska") 578 | USAleutian = Timezone("US/Aleutian") 579 | USArizona = Timezone("US/Arizona") 580 | USCentral = Timezone("US/Central") 581 | USEastern = Timezone("US/Eastern") 582 | USEastIndiana = Timezone("US/East-Indiana") 583 | USHawaii = Timezone("US/Hawaii") 584 | USIndianaStarke = Timezone("US/Indiana-Starke") 585 | USMichigan = Timezone("US/Michigan") 586 | USMountain = Timezone("US/Mountain") 587 | USPacific = Timezone("US/Pacific") 588 | USPacificNew = Timezone("US/Pacific-New") 589 | USSamoa = Timezone("US/Samoa") 590 | UTC = Timezone("UTC") 591 | WET = Timezone("WET") 592 | WSU = Timezone("W-SU") 593 | Zulu = Timezone("Zulu") 594 | ) 595 | -------------------------------------------------------------------------------- /timezone_test.go: -------------------------------------------------------------------------------- 1 | package gostradamus 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestTimezone_Location(t *testing.T) { 9 | actual := Timezone("notexist") 10 | assert.PanicsWithError( 11 | t, 12 | "unknown time zone notexist", 13 | func() { 14 | actual.Location() 15 | }, 16 | ) 17 | } 18 | --------------------------------------------------------------------------------