Ryan Hollis 7 éve
szülő
commit
78108ea9cb
1 módosított fájl, 52 hozzáadás és 19 törlés
  1. 52 19
      date.go

+ 52 - 19
date.go

@@ -5,9 +5,33 @@ import (
 	"time"
 )
 
-const MJD_0 float64 = 2400000.5
-const MJD_JD2000 float64 = 51544.5
-const MDD int64 = 106750	// Max Duration Days
+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 {
@@ -79,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
@@ -93,22 +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 = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC)
+		date = excel1904Epoc
 	} else {
-		date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
-	}	
-
-	// Duration is limited to aprox. 290 years
-	for intPart > MDD {
-		durationDays := time.Duration(MDD) * time.Hour * 24
-		date = date.Add(durationDays)
-		intPart = intPart - MDD
+		date = excel1900Epoc
 	}
+	durationPart := time.Duration(nanosInADay * floatPart)
+	return date.AddDate(0,0, wholeDaysPart).Add(durationPart)
+}
 
-	durationDays := time.Duration(intPart) * time.Hour * 24
-	durationPart := time.Duration(dayNanoSeconds * floatPart)
-	return date.Add(durationDays).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 {
+		offsetDays = daysBetween1970And1904
+	} else {
+		offsetDays = daysBetween1970And1900
+	}
+	daysSinceExcelEpoc := daysSinceUnixEpoc + offsetDays + nanosPart
+	return daysSinceExcelEpoc
 }