diff options
author | Ri Xu <xuri.me@gmail.com> | 2017-05-05 14:40:28 +0800 |
---|---|---|
committer | Ri Xu <xuri.me@gmail.com> | 2017-05-05 14:40:28 +0800 |
commit | 8fbab474443393b8b996487cf7ade300a72d2e07 (patch) | |
tree | bd863a7e6066ce62ecc01db110e508145057d3c9 /date.go | |
parent | 7f30a6c9430476bcd5fc1662523ada0e95f60947 (diff) |
- Formatted cell data support, fix issue #48;
- Function `SetCellValue()` support `time.Time` data type parameter, relate issue #49;
- go doc and go test updated
Diffstat (limited to 'date.go')
-rw-r--r-- | date.go | 119 |
1 files changed, 119 insertions, 0 deletions
@@ -0,0 +1,119 @@ +package excelize + +import ( + "math" + "time" +) + +// timeLocationUTC defined the UTC time location. +var timeLocationUTC, _ = time.LoadLocation("UTC") + +// timeToUTCTime provides function to convert time to UTC time. +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) +} + +// timeToExcelTime provides function to convert time to Excel time. +func timeToExcelTime(t time.Time) float64 { + return float64(t.UnixNano())/8.64e13 + 25569.0 +} + +// shiftJulianToNoon provides function to process julian date to noon. +func shiftJulianToNoon(julianDays, julianFraction float64) (float64, float64) { + switch { + case -0.5 < julianFraction && julianFraction < 0.5: + julianFraction += 0.5 + case julianFraction >= 0.5: + julianDays++ + julianFraction -= 0.5 + case julianFraction <= -0.5: + julianDays-- + julianFraction += 1.5 + } + return julianDays, julianFraction +} + +// fractionOfADay provides function to return the integer values for hour, +// minutes, seconds and nanoseconds that comprised a given fraction of a day. +// values would round to 1 us. +func fractionOfADay(fraction float64) (hours, minutes, seconds, nanoseconds int) { + + const ( + c1us = 1e3 + c1s = 1e9 + c1day = 24 * 60 * 60 * c1s + ) + + frac := int64(c1day*fraction + c1us/2) + nanoseconds = int((frac%c1s)/c1us) * c1us + frac /= c1s + seconds = int(frac % 60) + frac /= 60 + minutes = int(frac % 60) + hours = int(frac / 60) + return +} + +// julianDateToGregorianTime provides function to convert julian date to +// gregorian time. +func julianDateToGregorianTime(part1, part2 float64) time.Time { + part1I, part1F := math.Modf(part1) + part2I, part2F := math.Modf(part2) + julianDays := part1I + part2I + julianFraction := part1F + part2F + julianDays, julianFraction = shiftJulianToNoon(julianDays, julianFraction) + day, month, year := doTheFliegelAndVanFlandernAlgorithm(int(julianDays)) + hours, minutes, seconds, nanoseconds := fractionOfADay(julianFraction) + return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC) +} + +// By this point generations of programmers have repeated the algorithm sent to +// the editor of "Communications of the ACM" in 1968 (published in CACM, volume +// 11, number 10, October 1968, p.657). None of those programmers seems to have +// found it necessary to explain the constants or variable names set out by +// Henry F. Fliegel and Thomas C. Van Flandern. Maybe one day I'll buy that +// jounal and expand an explanation here - that day is not today. +func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) { + l := jd + 68569 + n := (4 * l) / 146097 + l = l - (146097*n+3)/4 + i := (4000 * (l + 1)) / 1461001 + l = l - (1461*i)/4 + 31 + j := (80 * l) / 2447 + d := l - (2447*j)/80 + l = j / 11 + m := j + 2 - (12 * l) + y := 100*(n-49) + i + l + return d, m, y +} + +// timeFromExcelTime provides function to 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(excelTime) + // Excel uses Julian dates prior to March 1st 1900, and Gregorian + // thereafter. + if intPart <= 61 { + const OFFSET1900 = 15018.0 + const OFFSET1904 = 16480.0 + const MJD0 float64 = 2400000.5 + var date time.Time + if date1904 { + date = julianDateToGregorianTime(MJD0, excelTime+OFFSET1904) + } else { + date = julianDateToGregorianTime(MJD0, excelTime+OFFSET1900) + } + return date + } + var floatPart = excelTime - float64(intPart) + var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000 + if date1904 { + date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC) + } else { + date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC) + } + durationDays := time.Duration(intPart) * time.Hour * 24 + durationPart := time.Duration(dayNanoSeconds * floatPart) + return date.Add(durationDays).Add(durationPart) +} |