format_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package time_test
  5. import (
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. "testing/quick"
  11. . "time"
  12. )
  13. var nextStdChunkTests = []string{
  14. "(2006)-(01)-(02)T(15):(04):(05)(Z07:00)",
  15. "(2006)-(01)-(02) (002) (15):(04):(05)",
  16. "(2006)-(01) (002) (15):(04):(05)",
  17. "(2006)-(002) (15):(04):(05)",
  18. "(2006)(002)(01) (15):(04):(05)",
  19. "(2006)(002)(04) (15):(04):(05)",
  20. }
  21. func TestNextStdChunk(t *testing.T) {
  22. // Most bugs in Parse or Format boil down to problems with
  23. // the exact detection of format chunk boundaries in the
  24. // helper function nextStdChunk (here called as NextStdChunk).
  25. // This test checks nextStdChunk's behavior directly,
  26. // instead of needing to test it only indirectly through Parse/Format.
  27. // markChunks returns format with each detected
  28. // 'format chunk' parenthesized.
  29. // For example showChunks("2006-01-02") == "(2006)-(01)-(02)".
  30. markChunks := func(format string) string {
  31. // Note that NextStdChunk and StdChunkNames
  32. // are not part of time's public API.
  33. // They are exported in export_test for this test.
  34. out := ""
  35. for s := format; s != ""; {
  36. prefix, std, suffix := NextStdChunk(s)
  37. out += prefix
  38. if std > 0 {
  39. out += "(" + StdChunkNames[std] + ")"
  40. }
  41. s = suffix
  42. }
  43. return out
  44. }
  45. noParens := func(r rune) rune {
  46. if r == '(' || r == ')' {
  47. return -1
  48. }
  49. return r
  50. }
  51. for _, marked := range nextStdChunkTests {
  52. // marked is an expected output from markChunks.
  53. // If we delete the parens and pass it through markChunks,
  54. // we should get the original back.
  55. format := strings.Map(noParens, marked)
  56. out := markChunks(format)
  57. if out != marked {
  58. t.Errorf("nextStdChunk parses %q as %q, want %q", format, out, marked)
  59. }
  60. }
  61. }
  62. type TimeFormatTest struct {
  63. time Time
  64. formattedValue string
  65. }
  66. var rfc3339Formats = []TimeFormatTest{
  67. {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
  68. {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
  69. {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
  70. }
  71. func TestRFC3339Conversion(t *testing.T) {
  72. for _, f := range rfc3339Formats {
  73. if f.time.Format(RFC3339) != f.formattedValue {
  74. t.Error("RFC3339:")
  75. t.Errorf(" want=%+v", f.formattedValue)
  76. t.Errorf(" have=%+v", f.time.Format(RFC3339))
  77. }
  78. }
  79. }
  80. type FormatTest struct {
  81. name string
  82. format string
  83. result string
  84. }
  85. var formatTests = []FormatTest{
  86. {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
  87. {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
  88. {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
  89. {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
  90. {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
  91. {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
  92. {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
  93. {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
  94. {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
  95. {"Kitchen", Kitchen, "9:00PM"},
  96. {"am/pm", "3pm", "9pm"},
  97. {"AM/PM", "3PM", "9PM"},
  98. {"two-digit year", "06 01 02", "09 02 04"},
  99. // Three-letter months and days must not be followed by lower-case letter.
  100. {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
  101. // Time stamps, Fractional seconds.
  102. {"Stamp", Stamp, "Feb 4 21:00:57"},
  103. {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
  104. {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
  105. {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
  106. {"YearDay", "Jan 2 002 __2 2", "Feb 4 035 35 4"},
  107. }
  108. func TestFormat(t *testing.T) {
  109. // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009
  110. time := Unix(0, 1233810057012345600)
  111. for _, test := range formatTests {
  112. result := time.Format(test.format)
  113. if result != test.result {
  114. t.Errorf("%s expected %q got %q", test.name, test.result, result)
  115. }
  116. }
  117. }
  118. var goStringTests = []struct {
  119. in Time
  120. want string
  121. }{
  122. {Date(2009, February, 5, 5, 0, 57, 12345600, UTC),
  123. "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.UTC)"},
  124. {Date(2009, February, 5, 5, 0, 57, 12345600, Local),
  125. "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Local)"},
  126. {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Europe/Berlin", 3*60*60)),
  127. `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Europe/Berlin"))`,
  128. },
  129. {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Non-ASCII character ⏰", 3*60*60)),
  130. `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Non-ASCII character \xe2\x8f\xb0"))`,
  131. },
  132. }
  133. func TestGoString(t *testing.T) {
  134. // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009
  135. for _, tt := range goStringTests {
  136. if tt.in.GoString() != tt.want {
  137. t.Errorf("GoString (%q): got %q want %q", tt.in, tt.in.GoString(), tt.want)
  138. }
  139. }
  140. }
  141. // issue 12440.
  142. func TestFormatSingleDigits(t *testing.T) {
  143. time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC)
  144. test := FormatTest{"single digit format", "3:4:5", "4:5:6"}
  145. result := time.Format(test.format)
  146. if result != test.result {
  147. t.Errorf("%s expected %q got %q", test.name, test.result, result)
  148. }
  149. }
  150. func TestFormatShortYear(t *testing.T) {
  151. years := []int{
  152. -100001, -100000, -99999,
  153. -10001, -10000, -9999,
  154. -1001, -1000, -999,
  155. -101, -100, -99,
  156. -11, -10, -9,
  157. -1, 0, 1,
  158. 9, 10, 11,
  159. 99, 100, 101,
  160. 999, 1000, 1001,
  161. 9999, 10000, 10001,
  162. 99999, 100000, 100001,
  163. }
  164. for _, y := range years {
  165. time := Date(y, January, 1, 0, 0, 0, 0, UTC)
  166. result := time.Format("2006.01.02")
  167. var want string
  168. if y < 0 {
  169. // The 4 in %04d counts the - sign, so print -y instead
  170. // and introduce our own - sign.
  171. want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
  172. } else {
  173. want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
  174. }
  175. if result != want {
  176. t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
  177. }
  178. }
  179. }
  180. type ParseTest struct {
  181. name string
  182. format string
  183. value string
  184. hasTZ bool // contains a time zone
  185. hasWD bool // contains a weekday
  186. yearSign int // sign of year, -1 indicates the year is not present in the format
  187. fracDigits int // number of digits of fractional second
  188. }
  189. var parseTests = []ParseTest{
  190. {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
  191. {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
  192. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
  193. {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
  194. {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
  195. {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
  196. {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
  197. {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
  198. {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
  199. // Optional fractional seconds.
  200. {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
  201. {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
  202. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
  203. {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
  204. {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
  205. {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
  206. {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
  207. {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
  208. // Amount of white space should not matter.
  209. {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
  210. {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
  211. // Case should not matter
  212. {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
  213. {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
  214. // Fractional seconds.
  215. {"millisecond:: dot separator", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
  216. {"microsecond:: dot separator", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
  217. {"nanosecond:: dot separator", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
  218. {"millisecond:: comma separator", "Mon Jan _2 15:04:05,000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
  219. {"microsecond:: comma separator", "Mon Jan _2 15:04:05,000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
  220. {"nanosecond:: comma separator", "Mon Jan _2 15:04:05,000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
  221. // Leading zeros in other places should not be taken as fractional seconds.
  222. {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
  223. {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
  224. // Month and day names only match when not followed by a lower-case letter.
  225. {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
  226. // GMT with offset.
  227. {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
  228. // Accept any number of fractional second digits (including none) for .999...
  229. // In Go 1, .999... was completely ignored in the format, meaning the first two
  230. // cases would succeed, but the next four would not. Go 1.1 accepts all six.
  231. // decimal "." separator.
  232. {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
  233. {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
  234. {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
  235. {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
  236. {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
  237. {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
  238. // comma "," separator.
  239. {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
  240. {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
  241. {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
  242. {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
  243. {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
  244. {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
  245. // issue 4502.
  246. {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
  247. {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
  248. {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
  249. {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
  250. {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
  251. // Day of year.
  252. {"", "2006-01-02 002 15:04:05", "2010-02-04 035 21:00:57", false, false, 1, 0},
  253. {"", "2006-01 002 15:04:05", "2010-02 035 21:00:57", false, false, 1, 0},
  254. {"", "2006-002 15:04:05", "2010-035 21:00:57", false, false, 1, 0},
  255. {"", "200600201 15:04:05", "201003502 21:00:57", false, false, 1, 0},
  256. {"", "200600204 15:04:05", "201003504 21:00:57", false, false, 1, 0},
  257. }
  258. func TestParse(t *testing.T) {
  259. for _, test := range parseTests {
  260. time, err := Parse(test.format, test.value)
  261. if err != nil {
  262. t.Errorf("%s error: %v", test.name, err)
  263. } else {
  264. checkTime(time, &test, t)
  265. }
  266. }
  267. }
  268. // All parsed with ANSIC.
  269. var dayOutOfRangeTests = []struct {
  270. date string
  271. ok bool
  272. }{
  273. {"Thu Jan 99 21:00:57 2010", false},
  274. {"Thu Jan 31 21:00:57 2010", true},
  275. {"Thu Jan 32 21:00:57 2010", false},
  276. {"Thu Feb 28 21:00:57 2012", true},
  277. {"Thu Feb 29 21:00:57 2012", true},
  278. {"Thu Feb 29 21:00:57 2010", false},
  279. {"Thu Mar 31 21:00:57 2010", true},
  280. {"Thu Mar 32 21:00:57 2010", false},
  281. {"Thu Apr 30 21:00:57 2010", true},
  282. {"Thu Apr 31 21:00:57 2010", false},
  283. {"Thu May 31 21:00:57 2010", true},
  284. {"Thu May 32 21:00:57 2010", false},
  285. {"Thu Jun 30 21:00:57 2010", true},
  286. {"Thu Jun 31 21:00:57 2010", false},
  287. {"Thu Jul 31 21:00:57 2010", true},
  288. {"Thu Jul 32 21:00:57 2010", false},
  289. {"Thu Aug 31 21:00:57 2010", true},
  290. {"Thu Aug 32 21:00:57 2010", false},
  291. {"Thu Sep 30 21:00:57 2010", true},
  292. {"Thu Sep 31 21:00:57 2010", false},
  293. {"Thu Oct 31 21:00:57 2010", true},
  294. {"Thu Oct 32 21:00:57 2010", false},
  295. {"Thu Nov 30 21:00:57 2010", true},
  296. {"Thu Nov 31 21:00:57 2010", false},
  297. {"Thu Dec 31 21:00:57 2010", true},
  298. {"Thu Dec 32 21:00:57 2010", false},
  299. {"Thu Dec 00 21:00:57 2010", false},
  300. }
  301. func TestParseDayOutOfRange(t *testing.T) {
  302. for _, test := range dayOutOfRangeTests {
  303. _, err := Parse(ANSIC, test.date)
  304. switch {
  305. case test.ok && err == nil:
  306. // OK
  307. case !test.ok && err != nil:
  308. if !strings.Contains(err.Error(), "day out of range") {
  309. t.Errorf("%q: expected 'day' error, got %v", test.date, err)
  310. }
  311. case test.ok && err != nil:
  312. t.Errorf("%q: unexpected error: %v", test.date, err)
  313. case !test.ok && err == nil:
  314. t.Errorf("%q: expected 'day' error, got none", test.date)
  315. }
  316. }
  317. }
  318. // TestParseInLocation checks that the Parse and ParseInLocation
  319. // functions do not get confused by the fact that AST (Arabia Standard
  320. // Time) and AST (Atlantic Standard Time) are different time zones,
  321. // even though they have the same abbreviation.
  322. //
  323. // ICANN has been slowly phasing out invented abbreviation in favor of
  324. // numeric time zones (for example, the Asia/Baghdad time zone
  325. // abbreviation got changed from AST to +03 in the 2017a tzdata
  326. // release); but we still want to make sure that the time package does
  327. // not get confused on systems with slightly older tzdata packages.
  328. func TestParseInLocation(t *testing.T) {
  329. baghdad, err := LoadLocation("Asia/Baghdad")
  330. if err != nil {
  331. t.Fatal(err)
  332. }
  333. var t1, t2 Time
  334. t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
  335. if err != nil {
  336. t.Fatal(err)
  337. }
  338. _, offset := t1.Zone()
  339. // A zero offset means that ParseInLocation did not recognize the
  340. // 'AST' abbreviation as matching the current location (Baghdad,
  341. // where we'd expect a +03 hrs offset); likely because we're using
  342. // a recent tzdata release (2017a or newer).
  343. // If it happens, skip the Baghdad test.
  344. if offset != 0 {
  345. t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad)
  346. if t1 != t2 {
  347. t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
  348. }
  349. if offset != 3*60*60 {
  350. t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
  351. }
  352. }
  353. blancSablon, err := LoadLocation("America/Blanc-Sablon")
  354. if err != nil {
  355. t.Fatal(err)
  356. }
  357. // In this case 'AST' means 'Atlantic Standard Time', and we
  358. // expect the abbreviation to correctly match the american
  359. // location.
  360. t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
  361. if err != nil {
  362. t.Fatal(err)
  363. }
  364. t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon)
  365. if t1 != t2 {
  366. t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2)
  367. }
  368. _, offset = t1.Zone()
  369. if offset != -4*60*60 {
  370. t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60)
  371. }
  372. }
  373. func TestLoadLocationZipFile(t *testing.T) {
  374. t.Skip("gccgo does not use the zip file")
  375. ForceZipFileForTesting(true)
  376. defer ForceZipFileForTesting(false)
  377. _, err := LoadLocation("Australia/Sydney")
  378. if err != nil {
  379. t.Fatal(err)
  380. }
  381. }
  382. var rubyTests = []ParseTest{
  383. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
  384. // Ignore the time zone in the test. If it parses, it'll be OK.
  385. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
  386. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
  387. {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
  388. }
  389. // Problematic time zone format needs special tests.
  390. func TestRubyParse(t *testing.T) {
  391. for _, test := range rubyTests {
  392. time, err := Parse(test.format, test.value)
  393. if err != nil {
  394. t.Errorf("%s error: %v", test.name, err)
  395. } else {
  396. checkTime(time, &test, t)
  397. }
  398. }
  399. }
  400. func checkTime(time Time, test *ParseTest, t *testing.T) {
  401. // The time should be Thu Feb 4 21:00:57 PST 2010
  402. if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
  403. t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
  404. }
  405. if time.Month() != February {
  406. t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
  407. }
  408. if time.Day() != 4 {
  409. t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
  410. }
  411. if time.Hour() != 21 {
  412. t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
  413. }
  414. if time.Minute() != 0 {
  415. t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
  416. }
  417. if time.Second() != 57 {
  418. t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
  419. }
  420. // Nanoseconds must be checked against the precision of the input.
  421. nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
  422. if err != nil {
  423. panic(err)
  424. }
  425. if time.Nanosecond() != int(nanosec) {
  426. t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
  427. }
  428. name, offset := time.Zone()
  429. if test.hasTZ && offset != -28800 {
  430. t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
  431. }
  432. if test.hasWD && time.Weekday() != Thursday {
  433. t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
  434. }
  435. }
  436. func TestFormatAndParse(t *testing.T) {
  437. const fmt = "Mon MST " + RFC3339 // all fields
  438. f := func(sec int64) bool {
  439. t1 := Unix(sec/2, 0)
  440. if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec {
  441. // not required to work
  442. return true
  443. }
  444. t2, err := Parse(fmt, t1.Format(fmt))
  445. if err != nil {
  446. t.Errorf("error: %s", err)
  447. return false
  448. }
  449. if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
  450. t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
  451. return false
  452. }
  453. return true
  454. }
  455. f32 := func(sec int32) bool { return f(int64(sec)) }
  456. cfg := &quick.Config{MaxCount: 10000}
  457. // Try a reasonable date first, then the huge ones.
  458. if err := quick.Check(f32, cfg); err != nil {
  459. t.Fatal(err)
  460. }
  461. if err := quick.Check(f, cfg); err != nil {
  462. t.Fatal(err)
  463. }
  464. }
  465. type ParseTimeZoneTest struct {
  466. value string
  467. length int
  468. ok bool
  469. }
  470. var parseTimeZoneTests = []ParseTimeZoneTest{
  471. {"gmt hi there", 0, false},
  472. {"GMT hi there", 3, true},
  473. {"GMT+12 hi there", 6, true},
  474. {"GMT+00 hi there", 6, true},
  475. {"GMT+", 3, true},
  476. {"GMT+3", 5, true},
  477. {"GMT+a", 3, true},
  478. {"GMT+3a", 5, true},
  479. {"GMT-5 hi there", 5, true},
  480. {"GMT-51 hi there", 3, true},
  481. {"ChST hi there", 4, true},
  482. {"MeST hi there", 4, true},
  483. {"MSDx", 3, true},
  484. {"MSDY", 0, false}, // four letters must end in T.
  485. {"ESAST hi", 5, true},
  486. {"ESASTT hi", 0, false}, // run of upper-case letters too long.
  487. {"ESATY hi", 0, false}, // five letters must end in T.
  488. {"WITA hi", 4, true}, // Issue #18251
  489. // Issue #24071
  490. {"+03 hi", 3, true},
  491. {"-04 hi", 3, true},
  492. // Issue #26032
  493. {"+00", 3, true},
  494. {"-11", 3, true},
  495. {"-12", 3, true},
  496. {"-23", 3, true},
  497. {"-24", 0, false},
  498. {"+13", 3, true},
  499. {"+14", 3, true},
  500. {"+23", 3, true},
  501. {"+24", 0, false},
  502. }
  503. func TestParseTimeZone(t *testing.T) {
  504. for _, test := range parseTimeZoneTests {
  505. length, ok := ParseTimeZone(test.value)
  506. if ok != test.ok {
  507. t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
  508. } else if length != test.length {
  509. t.Errorf("expected %d for %q got %d", test.length, test.value, length)
  510. }
  511. }
  512. }
  513. type ParseErrorTest struct {
  514. format string
  515. value string
  516. expect string // must appear within the error
  517. }
  518. var parseErrorTests = []ParseErrorTest{
  519. {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
  520. {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
  521. {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
  522. {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
  523. {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
  524. {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
  525. {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
  526. {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
  527. // issue 4502. StampNano requires exactly 9 digits of precision.
  528. {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
  529. {StampNano, "Dec 7 11:22:01.0000000000", `extra text: "0"`},
  530. // issue 4493. Helpful errors.
  531. {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: "07:00"`},
  532. {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
  533. {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
  534. {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: "_abc"`},
  535. // invalid second followed by optional fractional seconds
  536. {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
  537. // issue 21113
  538. {"_2 Jan 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
  539. {"_2 January 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
  540. // invalid or mismatched day-of-year
  541. {"Jan _2 002 2006", "Feb 4 034 2006", "day-of-year does not match day"},
  542. {"Jan _2 002 2006", "Feb 4 004 2006", "day-of-year does not match month"},
  543. // issue 45391.
  544. {`"2006-01-02T15:04:05Z07:00"`, "0", `parsing time "0" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse "0" as "\""`},
  545. {RFC3339, "\"", `parsing time "\"" as "2006-01-02T15:04:05Z07:00": cannot parse "\"" as "2006"`},
  546. }
  547. func TestParseErrors(t *testing.T) {
  548. for _, test := range parseErrorTests {
  549. _, err := Parse(test.format, test.value)
  550. if err == nil {
  551. t.Errorf("expected error for %q %q", test.format, test.value)
  552. } else if !strings.Contains(err.Error(), test.expect) {
  553. t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
  554. }
  555. }
  556. }
  557. func TestNoonIs12PM(t *testing.T) {
  558. noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
  559. const expect = "12:00PM"
  560. got := noon.Format("3:04PM")
  561. if got != expect {
  562. t.Errorf("got %q; expect %q", got, expect)
  563. }
  564. got = noon.Format("03:04PM")
  565. if got != expect {
  566. t.Errorf("got %q; expect %q", got, expect)
  567. }
  568. }
  569. func TestMidnightIs12AM(t *testing.T) {
  570. midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
  571. expect := "12:00AM"
  572. got := midnight.Format("3:04PM")
  573. if got != expect {
  574. t.Errorf("got %q; expect %q", got, expect)
  575. }
  576. got = midnight.Format("03:04PM")
  577. if got != expect {
  578. t.Errorf("got %q; expect %q", got, expect)
  579. }
  580. }
  581. func Test12PMIsNoon(t *testing.T) {
  582. noon, err := Parse("3:04PM", "12:00PM")
  583. if err != nil {
  584. t.Fatal("error parsing date:", err)
  585. }
  586. if noon.Hour() != 12 {
  587. t.Errorf("got %d; expect 12", noon.Hour())
  588. }
  589. noon, err = Parse("03:04PM", "12:00PM")
  590. if err != nil {
  591. t.Fatal("error parsing date:", err)
  592. }
  593. if noon.Hour() != 12 {
  594. t.Errorf("got %d; expect 12", noon.Hour())
  595. }
  596. }
  597. func Test12AMIsMidnight(t *testing.T) {
  598. midnight, err := Parse("3:04PM", "12:00AM")
  599. if err != nil {
  600. t.Fatal("error parsing date:", err)
  601. }
  602. if midnight.Hour() != 0 {
  603. t.Errorf("got %d; expect 0", midnight.Hour())
  604. }
  605. midnight, err = Parse("03:04PM", "12:00AM")
  606. if err != nil {
  607. t.Fatal("error parsing date:", err)
  608. }
  609. if midnight.Hour() != 0 {
  610. t.Errorf("got %d; expect 0", midnight.Hour())
  611. }
  612. }
  613. // Check that a time without a Zone still produces a (numeric) time zone
  614. // when formatted with MST as a requested zone.
  615. func TestMissingZone(t *testing.T) {
  616. time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
  617. if err != nil {
  618. t.Fatal("error parsing date:", err)
  619. }
  620. expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
  621. str := time.Format(UnixDate) // uses MST as its time zone
  622. if str != expect {
  623. t.Errorf("got %s; expect %s", str, expect)
  624. }
  625. }
  626. func TestMinutesInTimeZone(t *testing.T) {
  627. time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
  628. if err != nil {
  629. t.Fatal("error parsing date:", err)
  630. }
  631. expected := (1*60 + 23) * 60
  632. _, offset := time.Zone()
  633. if offset != expected {
  634. t.Errorf("ZoneOffset = %d, want %d", offset, expected)
  635. }
  636. }
  637. type SecondsTimeZoneOffsetTest struct {
  638. format string
  639. value string
  640. expectedoffset int
  641. }
  642. var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
  643. {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
  644. {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
  645. {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
  646. {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
  647. {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
  648. {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
  649. {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60},
  650. {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
  651. {"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
  652. }
  653. func TestParseSecondsInTimeZone(t *testing.T) {
  654. // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58
  655. for _, test := range secondsTimeZoneOffsetTests {
  656. time, err := Parse(test.format, test.value)
  657. if err != nil {
  658. t.Fatal("error parsing date:", err)
  659. }
  660. _, offset := time.Zone()
  661. if offset != test.expectedoffset {
  662. t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
  663. }
  664. }
  665. }
  666. func TestFormatSecondsInTimeZone(t *testing.T) {
  667. for _, test := range secondsTimeZoneOffsetTests {
  668. d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset))
  669. timestr := d.Format(test.format)
  670. if timestr != test.value {
  671. t.Errorf("Format = %s, want %s", timestr, test.value)
  672. }
  673. }
  674. }
  675. // Issue 11334.
  676. func TestUnderscoreTwoThousand(t *testing.T) {
  677. format := "15:04_20060102"
  678. input := "14:38_20150618"
  679. time, err := Parse(format, input)
  680. if err != nil {
  681. t.Error(err)
  682. }
  683. if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 {
  684. t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d)
  685. }
  686. if h := time.Hour(); h != 14 {
  687. t.Errorf("Incorrect hour, got %d", h)
  688. }
  689. if m := time.Minute(); m != 38 {
  690. t.Errorf("Incorrect minute, got %d", m)
  691. }
  692. }
  693. // Issue 29918, 29916
  694. func TestStd0xParseError(t *testing.T) {
  695. tests := []struct {
  696. format, value, valueElemPrefix string
  697. }{
  698. {"01 MST", "0 MST", "0"},
  699. {"01 MST", "1 MST", "1"},
  700. {RFC850, "Thursday, 04-Feb-1 21:00:57 PST", "1"},
  701. }
  702. for _, tt := range tests {
  703. _, err := Parse(tt.format, tt.value)
  704. if err == nil {
  705. t.Errorf("Parse(%q, %q) did not fail as expected", tt.format, tt.value)
  706. } else if perr, ok := err.(*ParseError); !ok {
  707. t.Errorf("Parse(%q, %q) returned error type %T, expected ParseError", tt.format, tt.value, perr)
  708. } else if !strings.Contains(perr.Error(), "cannot parse") || !strings.HasPrefix(perr.ValueElem, tt.valueElemPrefix) {
  709. t.Errorf("Parse(%q, %q) returned wrong parsing error message: %v", tt.format, tt.value, perr)
  710. }
  711. }
  712. }
  713. var monthOutOfRangeTests = []struct {
  714. value string
  715. ok bool
  716. }{
  717. {"00-01", false},
  718. {"13-01", false},
  719. {"01-01", true},
  720. }
  721. func TestParseMonthOutOfRange(t *testing.T) {
  722. for _, test := range monthOutOfRangeTests {
  723. _, err := Parse("01-02", test.value)
  724. switch {
  725. case !test.ok && err != nil:
  726. if !strings.Contains(err.Error(), "month out of range") {
  727. t.Errorf("%q: expected 'month' error, got %v", test.value, err)
  728. }
  729. case test.ok && err != nil:
  730. t.Errorf("%q: unexpected error: %v", test.value, err)
  731. case !test.ok && err == nil:
  732. t.Errorf("%q: expected 'month' error, got none", test.value)
  733. }
  734. }
  735. }
  736. // Issue 37387.
  737. func TestParseYday(t *testing.T) {
  738. t.Parallel()
  739. for i := 1; i <= 365; i++ {
  740. d := fmt.Sprintf("2020-%03d", i)
  741. tm, err := Parse("2006-002", d)
  742. if err != nil {
  743. t.Errorf("unexpected error for %s: %v", d, err)
  744. } else if tm.Year() != 2020 || tm.YearDay() != i {
  745. t.Errorf("got year %d yearday %d, want %d %d", tm.Year(), tm.YearDay(), 2020, i)
  746. }
  747. }
  748. }
  749. // Issue 45391.
  750. func TestQuote(t *testing.T) {
  751. tests := []struct {
  752. s, want string
  753. }{
  754. {`"`, `"\""`},
  755. {`abc"xyz"`, `"abc\"xyz\""`},
  756. {"", `""`},
  757. {"abc", `"abc"`},
  758. {`☺`, `"\xe2\x98\xba"`},
  759. {`☺ hello ☺ hello`, `"\xe2\x98\xba hello \xe2\x98\xba hello"`},
  760. {"\x04", `"\x04"`},
  761. }
  762. for _, tt := range tests {
  763. if q := Quote(tt.s); q != tt.want {
  764. t.Errorf("Quote(%q) = got %q, want %q", tt.s, q, tt.want)
  765. }
  766. }
  767. }
  768. // Issue 48037
  769. func TestFormatFractionalSecondSeparators(t *testing.T) {
  770. tests := []struct {
  771. s, want string
  772. }{
  773. {`15:04:05.000`, `21:00:57.012`},
  774. {`15:04:05.999`, `21:00:57.012`},
  775. {`15:04:05,000`, `21:00:57,012`},
  776. {`15:04:05,999`, `21:00:57,012`},
  777. }
  778. // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009
  779. time := Unix(0, 1233810057012345600)
  780. for _, tt := range tests {
  781. if q := time.Format(tt.s); q != tt.want {
  782. t.Errorf("Format(%q) = got %q, want %q", tt.s, q, tt.want)
  783. }
  784. }
  785. }
  786. // Issue 48685
  787. func TestParseFractionalSecondsLongerThanNineDigits(t *testing.T) {
  788. tests := []struct {
  789. s string
  790. want int
  791. }{
  792. // 9 digits
  793. {"2021-09-29T16:04:33.000000000Z", 0},
  794. {"2021-09-29T16:04:33.000000001Z", 1},
  795. {"2021-09-29T16:04:33.100000000Z", 100_000_000},
  796. {"2021-09-29T16:04:33.100000001Z", 100_000_001},
  797. {"2021-09-29T16:04:33.999999999Z", 999_999_999},
  798. {"2021-09-29T16:04:33.012345678Z", 12_345_678},
  799. // 10 digits, truncates
  800. {"2021-09-29T16:04:33.0000000000Z", 0},
  801. {"2021-09-29T16:04:33.0000000001Z", 0},
  802. {"2021-09-29T16:04:33.1000000000Z", 100_000_000},
  803. {"2021-09-29T16:04:33.1000000009Z", 100_000_000},
  804. {"2021-09-29T16:04:33.9999999999Z", 999_999_999},
  805. {"2021-09-29T16:04:33.0123456789Z", 12_345_678},
  806. // 11 digits, truncates
  807. {"2021-09-29T16:04:33.10000000000Z", 100_000_000},
  808. {"2021-09-29T16:04:33.00123456789Z", 1_234_567},
  809. // 12 digits, truncates
  810. {"2021-09-29T16:04:33.000123456789Z", 123_456},
  811. // 15 digits, truncates
  812. {"2021-09-29T16:04:33.9999999999999999Z", 999_999_999},
  813. }
  814. for _, tt := range tests {
  815. tm, err := Parse(RFC3339, tt.s)
  816. if err != nil {
  817. t.Errorf("Unexpected error: %v", err)
  818. continue
  819. }
  820. if got := tm.Nanosecond(); got != tt.want {
  821. t.Errorf("Parse(%q) = got %d, want %d", tt.s, got, tt.want)
  822. }
  823. }
  824. }