|
|
@@ -5,8 +5,33 @@ import (
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
-const MJD_0 float64 = 2400000.5
|
|
|
-const MJD_JD2000 float64 = 51544.5
|
|
|
+const (
|
|
|
+ MJD_0 float64 = 2400000.5
|
|
|
+ MJD_JD2000 float64 = 51544.5
|
|
|
+
|
|
|
+ secondsInADay = float64((24*time.Hour)/time.Second)
|
|
|
+ nanosInADay = float64((24*time.Hour)/time.Nanosecond)
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ timeLocationUTC, _ = time.LoadLocation("UTC")
|
|
|
+
|
|
|
+ unixEpoc = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
|
+ // In 1900 mode, Excel takes dates in floating point numbers of days starting with Jan 1 1900.
|
|
|
+ // The days are not zero indexed, so Jan 1 1900 would be 1.
|
|
|
+ // Except that Excel pretends that Feb 29, 1900 occurred to be compatible with a bug in Lotus 123.
|
|
|
+ // So, this constant uses Dec 30, 1899 instead of Jan 1, 1900, so the diff will be correct.
|
|
|
+ // http://www.cpearson.com/excel/datetime.htm
|
|
|
+ excel1900Epoc = time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC)
|
|
|
+ excel1904Epoc = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
|
+ // Days between epocs, including both off by one errors for 1900.
|
|
|
+ daysBetween1970And1900 = float64(unixEpoc.Sub(excel1900Epoc)/(24 * time.Hour))
|
|
|
+ daysBetween1970And1904 = float64(unixEpoc.Sub(excel1904Epoc)/(24 * time.Hour))
|
|
|
+)
|
|
|
+
|
|
|
+func TimeToUTCTime(t time.Time) time.Time {
|
|
|
+ return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
|
|
|
+}
|
|
|
|
|
|
func shiftJulianToNoon(julianDays, julianFraction float64) (float64, float64) {
|
|
|
switch {
|
|
|
@@ -78,10 +103,10 @@ func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) {
|
|
|
// Convert an excelTime representation (stored as a floating point number) to a time.Time.
|
|
|
func TimeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
|
|
var date time.Time
|
|
|
- var intPart int64 = int64(excelTime)
|
|
|
+ var wholeDaysPart = int(excelTime)
|
|
|
// Excel uses Julian dates prior to March 1st 1900, and
|
|
|
// Gregorian thereafter.
|
|
|
- if intPart <= 61 {
|
|
|
+ if wholeDaysPart <= 61 {
|
|
|
const OFFSET1900 = 15018.0
|
|
|
const OFFSET1904 = 16480.0
|
|
|
var date time.Time
|
|
|
@@ -92,14 +117,31 @@ func TimeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
|
|
}
|
|
|
return date
|
|
|
}
|
|
|
- var floatPart float64 = excelTime - float64(intPart)
|
|
|
- var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000
|
|
|
+ var floatPart = excelTime - float64(wholeDaysPart)
|
|
|
+ if date1904 {
|
|
|
+ date = excel1904Epoc
|
|
|
+ } else {
|
|
|
+ date = excel1900Epoc
|
|
|
+ }
|
|
|
+ durationPart := time.Duration(nanosInADay * floatPart)
|
|
|
+ return date.AddDate(0,0, wholeDaysPart).Add(durationPart)
|
|
|
+}
|
|
|
+
|
|
|
+// TimeToExcelTime will convert a time.Time into Excel's float representation, in either 1900 or 1904
|
|
|
+// mode. If you don't know which to use, set date1904 to false.
|
|
|
+// TODO should this should handle Julian dates?
|
|
|
+func TimeToExcelTime(t time.Time, date1904 bool) float64 {
|
|
|
+ // Get the number of days since the unix epoc
|
|
|
+ daysSinceUnixEpoc := float64(t.Unix())/secondsInADay
|
|
|
+ // Get the number of nanoseconds in days since Unix() is in seconds.
|
|
|
+ nanosPart := float64(t.Nanosecond())/nanosInADay
|
|
|
+ // Add both together plus the number of days difference between unix and Excel epocs.
|
|
|
+ var offsetDays float64
|
|
|
if date1904 {
|
|
|
- date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
+ offsetDays = daysBetween1970And1904
|
|
|
} else {
|
|
|
- date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
|
|
|
+ offsetDays = daysBetween1970And1900
|
|
|
}
|
|
|
- durationDays := time.Duration(intPart) * time.Hour * 24
|
|
|
- durationPart := time.Duration(dayNanoSeconds * floatPart)
|
|
|
- return date.Add(durationDays).Add(durationPart)
|
|
|
+ daysSinceExcelEpoc := daysSinceUnixEpoc + offsetDays + nanosPart
|
|
|
+ return daysSinceExcelEpoc
|
|
|
}
|