github.com/richardwilkes/toolbox@v1.121.0/formats/xlsx/datetime.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package xlsx 11 12 import ( 13 "math" 14 "time" 15 ) 16 17 // TimeFromExcelTime convertx an Excel time representation to a time.Time. Code for date/time conversion adapted from 18 // github.com/tealeg/xlsx. 19 func timeFromExcelTime(excelTime float64) time.Time { 20 var date time.Time 21 intPart := int64(excelTime) 22 // Excel uses Julian dates prior to March 1st 1900, and 23 // Gregorian thereafter. 24 if intPart <= 61 { 25 return julianDateToGregorianTime(2400000.5, excelTime+15018.0) 26 } 27 floatPart := excelTime - float64(intPart) 28 var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000 29 date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC) 30 durationDays := time.Duration(intPart) * time.Hour * 24 31 durationPart := time.Duration(dayNanoSeconds * floatPart) 32 return date.Add(durationDays).Add(durationPart) 33 } 34 35 func julianDateToGregorianTime(part1, part2 float64) time.Time { 36 part1I, part1F := math.Modf(part1) 37 part2I, part2F := math.Modf(part2) 38 julianDays := part1I + part2I 39 julianFraction := part1F + part2F 40 julianDays, julianFraction = shiftJulianToNoon(julianDays, julianFraction) 41 day, month, year := fliegelAndVanFlandernAlgorithm(int(julianDays)) 42 hours, minutes, seconds, nanoseconds := fractionOfADay(julianFraction) 43 return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC) 44 } 45 46 func shiftJulianToNoon(julianDays, julianFraction float64) (julianDaysResult, julianFractionResult float64) { 47 switch { 48 case -0.5 < julianFraction && julianFraction < 0.5: 49 julianFraction += 0.5 50 case julianFraction >= 0.5: 51 julianDays++ 52 julianFraction -= 0.5 53 case julianFraction <= -0.5: 54 julianDays-- 55 julianFraction += 1.5 56 } 57 return julianDays, julianFraction 58 } 59 60 func fliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) { 61 l := jd + 68569 62 n := (4 * l) / 146097 63 l -= (146097*n + 3) / 4 64 i := (4000 * (l + 1)) / 1461001 65 l = l - (1461*i)/4 + 31 66 j := (80 * l) / 2447 67 d := l - (2447*j)/80 68 l = j / 11 69 m := j + 2 - (12 * l) 70 y := 100*(n-49) + i + l 71 return d, m, y 72 } 73 74 func fractionOfADay(fraction float64) (hours, minutes, seconds, nanoseconds int) { 75 const ( 76 c1us = 1e3 77 c1s = 1e9 78 ) 79 frac := int64(24*60*60*c1s*fraction + c1us/2) 80 nanoseconds = int((frac%c1s)/c1us) * c1us 81 frac /= c1s 82 seconds = int(frac % 60) 83 frac /= 60 84 minutes = int(frac % 60) 85 hours = int(frac / 60) 86 return 87 }