github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/timeutil/pgdate/pgdate_test.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package pgdate
    12  
    13  import (
    14  	"fmt"
    15  	"math"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  func TestParseDate(t *testing.T) {
    22  	for _, tc := range []struct {
    23  		s      string
    24  		err    string
    25  		pgdays int32
    26  	}{
    27  		{
    28  			s:      "2000-01-01",
    29  			pgdays: 0,
    30  		},
    31  		{
    32  			s:      "1999-12-31",
    33  			pgdays: -1,
    34  		},
    35  		{
    36  			s:      "2000-01-02",
    37  			pgdays: 1,
    38  		},
    39  		{
    40  			s:      "0001-01-01",
    41  			pgdays: -730119,
    42  		},
    43  		{
    44  			s:      "0001-12-31 BC",
    45  			pgdays: -730120,
    46  		},
    47  		{
    48  			s:      "0002-01-01 BC",
    49  			pgdays: -730850,
    50  		},
    51  		{
    52  			s:      "5874897-12-31",
    53  			pgdays: highDays,
    54  		},
    55  		{
    56  			s:      "4714-11-24 BC",
    57  			pgdays: lowDays,
    58  		},
    59  		{
    60  			s:   "4714-11-23 BC",
    61  			err: "date is out of range",
    62  		},
    63  		{
    64  			s:   "5874898-01-01",
    65  			err: "date is out of range",
    66  		},
    67  		{
    68  			s:   "0000-01-01",
    69  			err: "year value 0 is out of range",
    70  		},
    71  	} {
    72  		t.Run(tc.s, func(t *testing.T) {
    73  			d, err := ParseDate(time.Time{}, ParseModeYMD, tc.s)
    74  			if tc.err != "" {
    75  				if err == nil || !strings.Contains(err.Error(), tc.err) {
    76  					t.Fatalf("got %v, expected %v", err, tc.err)
    77  				}
    78  				return
    79  			}
    80  			pg := d.PGEpochDays()
    81  			if pg != tc.pgdays {
    82  				t.Fatalf("%d != %d", pg, tc.pgdays)
    83  			}
    84  			s := d.String()
    85  			if s != tc.s {
    86  				t.Fatalf("%s != %s", s, tc.s)
    87  			}
    88  		})
    89  	}
    90  }
    91  
    92  func TestMakeCompatibleDateFromDisk(t *testing.T) {
    93  	for _, tc := range []struct {
    94  		in, out int64
    95  	}{
    96  		{0, 0},
    97  		{1, 1},
    98  		{-1, -1},
    99  		{math.MaxInt64, math.MaxInt64},
   100  		{math.MinInt64, math.MinInt64},
   101  		{math.MaxInt32, math.MaxInt64},
   102  		{math.MinInt32, math.MinInt64},
   103  	} {
   104  		t.Run(fmt.Sprint(tc.in), func(t *testing.T) {
   105  			date := MakeCompatibleDateFromDisk(tc.in)
   106  			orig := date.UnixEpochDaysWithOrig()
   107  			if orig != tc.in {
   108  				t.Fatalf("%d != %d", orig, tc.in)
   109  			}
   110  			days := date.UnixEpochDays()
   111  			if days != tc.out {
   112  				t.Fatalf("%d != %d", days, tc.out)
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestMakeDateFromTime(t *testing.T) {
   119  	pgEpoch := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
   120  	pgEpochWithHourOffset := time.Date(2000, 1, 1, 1, 0, 0, 0, time.UTC)
   121  	// These dates are negative, which makes rounding a little different.
   122  	dayBeforeUnixEpoch := time.Date(1969, 12, 31, 0, 0, 0, 0, time.UTC)
   123  	dayBeforeUnixEpochWithHourOffset := time.Date(1969, 12, 31, 1, 0, 0, 0, time.UTC)
   124  	twoDaysBeforeUnixEpoch := time.Date(1969, 12, 30, 0, 0, 0, 0, time.UTC)
   125  	twoDaysBeforeUnixEpochWithHourOffset := time.Date(1969, 12, 30, 1, 0, 0, 0, time.UTC)
   126  
   127  	for _, tc := range []struct {
   128  		in  time.Time
   129  		out string
   130  	}{
   131  		{pgEpoch.In(time.FixedZone("secsPerDay", secondsPerDay)), "2000-01-02"},
   132  		{pgEpoch.In(time.FixedZone("secsPerDay-1", secondsPerDay-1)), "2000-01-01"},
   133  		{pgEpoch.In(time.FixedZone("1", 1)), "2000-01-01"},
   134  		{pgEpoch, "2000-01-01"},
   135  		{pgEpoch.In(time.FixedZone("-1", -1)), "1999-12-31"},
   136  		{pgEpoch.In(time.FixedZone("-secsPerDay", -secondsPerDay)), "1999-12-31"},
   137  		{pgEpochWithHourOffset, "2000-01-01"},
   138  
   139  		{dayBeforeUnixEpoch, "1969-12-31"},
   140  		{dayBeforeUnixEpochWithHourOffset, "1969-12-31"},
   141  		{twoDaysBeforeUnixEpoch, "1969-12-30"},
   142  		{twoDaysBeforeUnixEpochWithHourOffset, "1969-12-30"},
   143  	} {
   144  		t.Run(tc.in.Format(time.RFC3339), func(t *testing.T) {
   145  			d, err := MakeDateFromTime(tc.in)
   146  			if err != nil {
   147  				t.Fatal(err)
   148  			}
   149  			exp := tc.in.Format("2006-01-02")
   150  			// Sanity check our tests.
   151  			if exp != tc.out {
   152  				t.Fatalf("got %s, expected %s", exp, tc.out)
   153  			}
   154  			s := d.String()
   155  			if exp != s {
   156  				t.Fatalf("got %s, expected %s", s, exp)
   157  			}
   158  		})
   159  	}
   160  }