2008-11-24 16:17:47 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2009-08-12 14:18:37 -06:00
|
|
|
package time_test
|
2008-11-24 16:17:47 -07:00
|
|
|
|
|
|
|
import (
|
2009-12-15 16:41:46 -07:00
|
|
|
"os"
|
2010-01-07 18:59:20 -07:00
|
|
|
"strings"
|
2009-12-15 16:41:46 -07:00
|
|
|
"testing"
|
|
|
|
"testing/quick"
|
|
|
|
. "time"
|
2008-11-24 16:17:47 -07:00
|
|
|
)
|
|
|
|
|
2009-02-15 23:12:35 -07:00
|
|
|
func init() {
|
|
|
|
// Force US Pacific time for daylight-savings
|
|
|
|
// tests below (localtests). Needs to be set
|
|
|
|
// before the first call into the time library.
|
2009-11-17 09:20:58 -07:00
|
|
|
os.Setenv("TZ", "America/Los_Angeles")
|
2009-02-15 23:12:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type TimeTest struct {
|
2009-12-15 16:41:46 -07:00
|
|
|
seconds int64
|
|
|
|
golden Time
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var utctests = []TimeTest{
|
2009-03-03 09:39:12 -07:00
|
|
|
TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
|
|
|
|
TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
|
|
|
|
TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
|
2009-12-02 00:38:06 -07:00
|
|
|
TimeTest{-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}},
|
2009-12-02 09:27:57 -07:00
|
|
|
TimeTest{599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}},
|
|
|
|
TimeTest{978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}},
|
2009-03-03 09:39:12 -07:00
|
|
|
TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
|
|
|
|
TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
|
|
|
|
TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
|
2009-10-08 16:14:54 -06:00
|
|
|
TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}},
|
2009-03-03 09:39:12 -07:00
|
|
|
}
|
2008-11-24 16:17:47 -07:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var localtests = []TimeTest{
|
|
|
|
TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
|
|
|
|
TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7 * 60 * 60, "PDT"}},
|
2009-03-03 09:39:12 -07:00
|
|
|
}
|
2008-11-24 16:17:47 -07:00
|
|
|
|
2009-02-15 23:12:35 -07:00
|
|
|
func same(t, u *Time) bool {
|
2009-10-08 16:14:54 -06:00
|
|
|
return t.Year == u.Year &&
|
|
|
|
t.Month == u.Month &&
|
|
|
|
t.Day == u.Day &&
|
|
|
|
t.Hour == u.Hour &&
|
|
|
|
t.Minute == u.Minute &&
|
|
|
|
t.Second == u.Second &&
|
|
|
|
t.Weekday == u.Weekday &&
|
|
|
|
t.ZoneOffset == u.ZoneOffset &&
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Zone == u.Zone
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestSecondsToUTC(t *testing.T) {
|
2008-11-24 16:17:47 -07:00
|
|
|
for i := 0; i < len(utctests); i++ {
|
2009-12-15 16:41:46 -07:00
|
|
|
sec := utctests[i].seconds
|
|
|
|
golden := &utctests[i].golden
|
|
|
|
tm := SecondsToUTC(sec)
|
|
|
|
newsec := tm.Seconds()
|
2008-11-24 16:17:47 -07:00
|
|
|
if newsec != sec {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
2009-02-15 23:12:35 -07:00
|
|
|
if !same(tm, golden) {
|
2009-12-15 16:41:46 -07:00
|
|
|
t.Errorf("SecondsToUTC(%d):", sec)
|
|
|
|
t.Errorf(" want=%+v", *golden)
|
|
|
|
t.Errorf(" have=%+v", *tm)
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestSecondsToLocalTime(t *testing.T) {
|
2008-11-24 16:17:47 -07:00
|
|
|
for i := 0; i < len(localtests); i++ {
|
2009-12-15 16:41:46 -07:00
|
|
|
sec := localtests[i].seconds
|
|
|
|
golden := &localtests[i].golden
|
|
|
|
tm := SecondsToLocalTime(sec)
|
|
|
|
newsec := tm.Seconds()
|
2008-11-24 16:17:47 -07:00
|
|
|
if newsec != sec {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
2009-02-15 23:12:35 -07:00
|
|
|
if !same(tm, golden) {
|
2009-12-15 16:41:46 -07:00
|
|
|
t.Errorf("SecondsToLocalTime(%d):", sec)
|
|
|
|
t.Errorf(" want=%+v", *golden)
|
|
|
|
t.Errorf(" have=%+v", *tm)
|
2008-11-24 16:17:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-24 01:21:50 -07:00
|
|
|
|
2009-12-02 09:27:57 -07:00
|
|
|
func TestSecondsToUTCAndBack(t *testing.T) {
|
2009-12-15 16:41:46 -07:00
|
|
|
f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
|
|
|
|
f32 := func(sec int32) bool { return f(int64(sec)) }
|
|
|
|
cfg := &quick.Config{MaxCount: 10000}
|
2009-12-02 09:27:57 -07:00
|
|
|
|
|
|
|
// Try a reasonable date first, then the huge ones.
|
|
|
|
if err := quick.Check(f32, cfg); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := quick.Check(f, cfg); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-17 14:39:13 -07:00
|
|
|
type TimeFormatTest struct {
|
|
|
|
time Time
|
|
|
|
formattedValue string
|
|
|
|
}
|
|
|
|
|
|
|
|
var iso8601Formats = []TimeFormatTest{
|
|
|
|
TimeFormatTest{Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
|
|
|
|
TimeFormatTest{Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-0500"},
|
|
|
|
TimeFormatTest{Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+0420"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestISO8601Conversion(t *testing.T) {
|
|
|
|
for _, f := range iso8601Formats {
|
2010-01-06 16:32:48 -07:00
|
|
|
if f.time.Format(ISO8601) != f.formattedValue {
|
|
|
|
t.Error("ISO8601:")
|
2009-12-17 14:39:13 -07:00
|
|
|
t.Errorf(" want=%+v", f.formattedValue)
|
2010-01-06 16:32:48 -07:00
|
|
|
t.Errorf(" have=%+v", f.time.Format(ISO8601))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type FormatTest struct {
|
|
|
|
name string
|
|
|
|
format string
|
|
|
|
result string
|
|
|
|
}
|
|
|
|
|
|
|
|
var formatTests = []FormatTest{
|
|
|
|
FormatTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010"},
|
|
|
|
FormatTest{"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010"},
|
|
|
|
FormatTest{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
|
|
|
|
FormatTest{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
|
|
|
|
FormatTest{"ISO8601", ISO8601, "2010-02-04T21:00:57-0800"},
|
|
|
|
FormatTest{"Kitchen", Kitchen, "9:00PM"},
|
|
|
|
FormatTest{"am/pm", "3pm", "9pm"},
|
|
|
|
FormatTest{"AM/PM", "3PM", "9PM"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormat(t *testing.T) {
|
2010-01-07 18:59:20 -07:00
|
|
|
// The numeric time represents Thu Feb 4 21:00:57 PST 2010
|
2010-01-06 16:32:48 -07:00
|
|
|
time := SecondsToLocalTime(1265346057)
|
|
|
|
for _, test := range formatTests {
|
|
|
|
result := time.Format(test.format)
|
|
|
|
if result != test.result {
|
|
|
|
t.Errorf("%s expected %q got %q", test.name, test.result, result)
|
2009-12-17 14:39:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-07 18:59:20 -07:00
|
|
|
type ParseTest struct {
|
|
|
|
name string
|
|
|
|
format string
|
|
|
|
value string
|
|
|
|
hasTZ bool // contains a time zone
|
|
|
|
hasWD bool // contains a weekday
|
|
|
|
}
|
|
|
|
|
|
|
|
var parseTests = []ParseTest{
|
|
|
|
ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true},
|
|
|
|
ParseTest{"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true},
|
|
|
|
ParseTest{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true},
|
|
|
|
ParseTest{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true},
|
|
|
|
ParseTest{"ISO8601", ISO8601, "2010-02-04T21:00:57-0800", true, false},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParse(t *testing.T) {
|
|
|
|
for _, test := range parseTests {
|
|
|
|
time, err := Parse(test.format, test.value)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%s error: %v", test.name, err)
|
|
|
|
} else {
|
|
|
|
checkTime(time, &test, t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkTime(time *Time, test *ParseTest, t *testing.T) {
|
|
|
|
// The time should be Thu Feb 4 21:00:57 PST 2010
|
|
|
|
if time.Year != 2010 {
|
|
|
|
t.Errorf("%s: bad year: %d not %d\n", test.name, time.Year, 2010)
|
|
|
|
}
|
|
|
|
if time.Month != 2 {
|
|
|
|
t.Errorf("%s: bad month: %d not %d\n", test.name, time.Month, 2)
|
|
|
|
}
|
|
|
|
if time.Day != 4 {
|
|
|
|
t.Errorf("%s: bad day: %d not %d\n", test.name, time.Day, 4)
|
|
|
|
}
|
|
|
|
if time.Hour != 21 {
|
|
|
|
t.Errorf("%s: bad hour: %d not %d\n", test.name, time.Hour, 21)
|
|
|
|
}
|
|
|
|
if time.Minute != 0 {
|
|
|
|
t.Errorf("%s: bad minute: %d not %d\n", test.name, time.Minute, 0)
|
|
|
|
}
|
|
|
|
if time.Second != 57 {
|
|
|
|
t.Errorf("%s: bad second: %d not %d\n", test.name, time.Second, 57)
|
|
|
|
}
|
|
|
|
if test.hasTZ && time.ZoneOffset != -28800 {
|
|
|
|
t.Errorf("%s: bad tz offset: %d not %d\n", test.name, time.ZoneOffset, -28800)
|
|
|
|
}
|
|
|
|
if test.hasWD && time.Weekday != 4 {
|
|
|
|
t.Errorf("%s: bad weekday: %d not %d\n", test.name, time.Weekday, 4)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormatAndParse(t *testing.T) {
|
|
|
|
const fmt = "Mon MST " + ISO8601 // all fields
|
|
|
|
f := func(sec int64) bool {
|
|
|
|
t1 := SecondsToLocalTime(sec)
|
|
|
|
t2, err := Parse(fmt, t1.Format(fmt))
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error: %s", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !same(t1, t2) {
|
|
|
|
t.Errorf("different: %q %q", t1, t2)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
f32 := func(sec int32) bool { return f(int64(sec)) }
|
|
|
|
cfg := &quick.Config{MaxCount: 10000}
|
|
|
|
|
|
|
|
// Try a reasonable date first, then the huge ones.
|
|
|
|
if err := quick.Check(f32, cfg); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := quick.Check(f, cfg); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ParseErrorTest struct {
|
|
|
|
format string
|
|
|
|
value string
|
|
|
|
expect string // must appear within the error
|
|
|
|
}
|
|
|
|
|
|
|
|
var parseErrorTests = []ParseErrorTest{
|
|
|
|
ParseErrorTest{ANSIC, "Feb 4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon
|
|
|
|
ParseErrorTest{ANSIC, "Thu Feb 4 21:00:57 @2010", "format"},
|
|
|
|
ParseErrorTest{ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
|
|
|
|
ParseErrorTest{ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
|
|
|
|
ParseErrorTest{ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParseErrors(t *testing.T) {
|
|
|
|
for _, test := range parseErrorTests {
|
|
|
|
_, err := Parse(test.format, test.value)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected error for %q %q\n", test.format, test.value)
|
|
|
|
} else if strings.Index(err.String(), test.expect) < 0 {
|
|
|
|
t.Errorf("expected error with %q for %q %q; got %s\n", test.expect, test.format, test.value, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-24 01:21:50 -07:00
|
|
|
func BenchmarkSeconds(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Seconds()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkNanoseconds(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Nanoseconds()
|
|
|
|
}
|
|
|
|
}
|
2010-01-06 20:36:54 -07:00
|
|
|
|
|
|
|
func BenchmarkFormat(b *testing.B) {
|
|
|
|
time := SecondsToLocalTime(1265346057)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
time.Format("Mon Jan 2 15:04:05 2006")
|
|
|
|
}
|
|
|
|
}
|
2010-01-07 18:59:20 -07:00
|
|
|
|
|
|
|
func BenchmarkParse(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
|
|
|
|
}
|
|
|
|
}
|