Skip to content

Commit af41c6a

Browse files
authored
DateTime function to convert to time.Time value (close #115) (#116)
1 parent a11a9ab commit af41c6a

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

types.go

+19
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"regexp"
1010
"strconv"
1111
"strings"
12+
"time"
1213
"unicode"
1314
)
1415

@@ -384,6 +385,24 @@ func ParseDate(ddmmyy string) (Date, error) {
384385
return Date{true, dd, mm, yy}, nil
385386
}
386387

388+
// DateTime converts the provided Date and Time values to a standard UTC time.Time.
389+
// The referenceYear parameter is used to determine the offset (century) for the two-digit year in Date.
390+
// For example, if the referenceYear is 2024, the offset used is 2000; and the input date's year is prepended with 20.
391+
// If referenceYear is 0, the current UTC year is used.
392+
// If either Date or Time is not valid, DateTime returns the zero time.Time.
393+
func DateTime(referenceYear int, d Date, t Time) time.Time {
394+
if !d.Valid || !t.Valid {
395+
return time.Time{}
396+
}
397+
if referenceYear == 0 {
398+
referenceYear = time.Now().UTC().Year()
399+
}
400+
century := referenceYear / 100 * 100 // truncate the last two digits (year within century); keep first two digits of the full year
401+
return time.Date(century+d.YY, time.Month(d.MM), d.DD,
402+
t.Hour, t.Minute, t.Second, t.Millisecond*1e6,
403+
time.UTC)
404+
}
405+
387406
// LatDir returns the latitude direction symbol
388407
func LatDir(l float64) string {
389408
if l < 0.0 {

types_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package nmea
33
import (
44
"fmt"
55
"testing"
6+
"time"
67

78
"github.com/stretchr/testify/assert"
89
)
@@ -220,6 +221,60 @@ func TestDateString(t *testing.T) {
220221
}
221222
}
222223

224+
func TestDateTime(t *testing.T) {
225+
for i, testCase := range []struct {
226+
refYear int
227+
date Date
228+
time Time
229+
expect time.Time
230+
}{
231+
{
232+
refYear: 2024,
233+
date: Date{DD: 1, MM: 2, YY: 3, Valid: true},
234+
time: Time{Hour: 1, Minute: 2, Second: 3, Millisecond: 4, Valid: true},
235+
expect: time.Date(2003, time.February, 1, 1, 2, 3, 4e6, time.UTC),
236+
},
237+
{
238+
refYear: 1999,
239+
date: Date{DD: 1, MM: 2, YY: 3, Valid: true},
240+
time: Time{Hour: 1, Minute: 2, Second: 3, Millisecond: 4, Valid: true},
241+
expect: time.Date(1903, time.February, 1, 1, 2, 3, 4e6, time.UTC),
242+
},
243+
{
244+
refYear: 2025,
245+
date: Date{DD: 23, MM: 7, YY: 24, Valid: true},
246+
time: Time{Hour: 18, Minute: 5, Second: 12, Millisecond: 1, Valid: true},
247+
expect: time.Date(2024, time.July, 23, 18, 5, 12, 1e6, time.UTC),
248+
},
249+
// zero reference year; this test will fail starting in the year 3000
250+
{
251+
refYear: 0,
252+
date: Date{DD: 1, MM: 2, YY: 3, Valid: true},
253+
time: Time{Hour: 1, Minute: 2, Second: 3, Millisecond: 4, Valid: true},
254+
expect: time.Date(2003, time.February, 1, 1, 2, 3, 4e6, time.UTC),
255+
},
256+
// invalid date
257+
{
258+
refYear: 2024,
259+
date: Date{DD: 1, MM: 2, YY: 3},
260+
time: Time{Hour: 1, Minute: 2, Second: 3, Millisecond: 4, Valid: true},
261+
expect: time.Time{},
262+
},
263+
// invalid time
264+
{
265+
refYear: 2024,
266+
date: Date{DD: 1, MM: 2, YY: 3, Valid: true},
267+
time: Time{Hour: 1, Minute: 2, Second: 3, Millisecond: 4},
268+
expect: time.Time{},
269+
},
270+
} {
271+
actual := DateTime(testCase.refYear, testCase.date, testCase.time)
272+
if !actual.Equal(testCase.expect) {
273+
t.Fatalf("Test %d (refYear=%d date=%s time=%s): Expected %s but got %s", i, testCase.refYear, testCase.date, testCase.time, testCase.expect, actual)
274+
}
275+
}
276+
}
277+
223278
func TestLatDir(t *testing.T) {
224279
tests := []struct {
225280
value float64

0 commit comments

Comments
 (0)