Buckets:
| /** | |
| * @license | |
| * Copyright 2024 The Emscripten Authors | |
| * SPDX-License-Identifier: MIT | |
| */ | |
| assert(!STANDALONE_WASM, "library_time.js should not be included in standalone mode"); | |
| addToLibrary({ | |
| _mktime_js__i53abi: true, | |
| _mktime_js__deps: ['$ydayFromDate'], | |
| _mktime_js: (tmPtr) => { | |
| var date = new Date({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, | |
| 0); | |
| if (isNaN(date.getTime())) { | |
| return -1; | |
| } | |
| // There's an ambiguous hour when the time goes back; the tm_isdst field is | |
| // used to disambiguate it. Date() basically guesses, so we fix it up if it | |
| // guessed wrong, or fill in tm_isdst with the guess if it's -1. | |
| var dst = {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'i32') }}}; | |
| var guessedOffset = date.getTimezoneOffset(); | |
| var start = new Date(date.getFullYear(), 0, 1); | |
| var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); | |
| var winterOffset = start.getTimezoneOffset(); | |
| var dstOffset = Math.min(winterOffset, summerOffset); // DST is in December in South | |
| if (dst < 0) { | |
| // Attention: some regions don't have DST at all. | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'Number(summerOffset != winterOffset && dstOffset == guessedOffset)', 'i32') }}}; | |
| } else if ((dst > 0) != (dstOffset == guessedOffset)) { | |
| var nonDstOffset = Math.max(winterOffset, summerOffset); | |
| var trueOffset = dst > 0 ? dstOffset : nonDstOffset; | |
| // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up. | |
| date.setTime(date.getTime() + (trueOffset - guessedOffset)*60000); | |
| } | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; | |
| var yday = ydayFromDate(date)|0; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; | |
| // To match expected behavior, update fields from date | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getYear()', 'i32') }}}; | |
| // Return time in seconds | |
| return date.getTime() / 1000; | |
| }, | |
| _gmtime_js__i53abi: true, | |
| _gmtime_js: (time, tmPtr) => { | |
| var date = new Date(time * 1000); | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}; | |
| var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); | |
| var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; | |
| }, | |
| _timegm_js__i53abi: true, | |
| _timegm_js: (tmPtr) => { | |
| var time = Date.UTC({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}}, | |
| {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, | |
| 0); | |
| var date = new Date(time); | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}; | |
| var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); | |
| var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; | |
| return date.getTime() / 1000; | |
| }, | |
| _localtime_js__i53abi: true, | |
| _localtime_js__deps: ['$ydayFromDate'], | |
| _localtime_js: (time, tmPtr) => { | |
| var date = new Date(time*1000); | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; | |
| var yday = ydayFromDate(date)|0; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '-(date.getTimezoneOffset() * 60)', LONG_TYPE) }}}; | |
| // Attention: DST is in December in South, and some regions don't have DST at all. | |
| var start = new Date(date.getFullYear(), 0, 1); | |
| var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); | |
| var winterOffset = start.getTimezoneOffset(); | |
| var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0; | |
| {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}; | |
| }, | |
| // musl-internal function used to implement both `asctime` and `asctime_r` | |
| __asctime_r: (tmPtr, buf) => { | |
| var date = { | |
| tm_sec: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, | |
| tm_min: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}}, | |
| tm_hour: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}}, | |
| tm_mday: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}}, | |
| tm_mon: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}}, | |
| tm_year: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}}, | |
| tm_wday: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'i32') }}} | |
| }; | |
| var days = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; | |
| var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; | |
| var s = days[date.tm_wday] + ' ' + months[date.tm_mon] + | |
| (date.tm_mday < 10 ? ' ' : ' ') + date.tm_mday + | |
| (date.tm_hour < 10 ? ' 0' : ' ') + date.tm_hour + | |
| (date.tm_min < 10 ? ':0' : ':') + date.tm_min + | |
| (date.tm_sec < 10 ? ':0' : ':') + date.tm_sec + | |
| ' ' + (1900 + date.tm_year) + "\n"; | |
| // asctime_r is specced to behave in an undefined manner if the algorithm would attempt | |
| // to write out more than 26 bytes (including the null terminator). | |
| // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html | |
| // Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator. | |
| stringToUTF8(s, buf, 26); | |
| return buf; | |
| }, | |
| _tzset_js__deps: ['$stringToUTF8', | |
| #if ASSERTIONS | |
| '$lengthBytesUTF8', | |
| #endif | |
| ], | |
| _tzset_js__internal: true, | |
| _tzset_js: (timezone, daylight, std_name, dst_name) => { | |
| // TODO: Use (malleable) environment variables instead of system settings. | |
| var currentYear = new Date().getFullYear(); | |
| var winter = new Date(currentYear, 0, 1); | |
| var summer = new Date(currentYear, 6, 1); | |
| var winterOffset = winter.getTimezoneOffset(); | |
| var summerOffset = summer.getTimezoneOffset(); | |
| // Local standard timezone offset. Local standard time is not adjusted for | |
| // daylight savings. This code uses the fact that getTimezoneOffset returns | |
| // a greater value during Standard Time versus Daylight Saving Time (DST). | |
| // Thus it determines the expected output during Standard Time, and it | |
| // compares whether the output of the given date the same (Standard) or less | |
| // (DST). | |
| var stdTimezoneOffset = Math.max(winterOffset, summerOffset); | |
| // timezone is specified as seconds west of UTC ("The external variable | |
| // `timezone` shall be set to the difference, in seconds, between | |
| // Coordinated Universal Time (UTC) and local standard time."), the same | |
| // as returned by stdTimezoneOffset. | |
| // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html | |
| {{{ makeSetValue('timezone', '0', 'stdTimezoneOffset * 60', '*') }}}; | |
| {{{ makeSetValue('daylight', '0', 'Number(winterOffset != summerOffset)', 'i32') }}}; | |
| var extractZone = (timezoneOffset) => { | |
| // Why inverse sign? | |
| // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset | |
| var sign = timezoneOffset >= 0 ? "-" : "+"; | |
| var absOffset = Math.abs(timezoneOffset) | |
| var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); | |
| var minutes = String(absOffset % 60).padStart(2, "0"); | |
| return `UTC${sign}${hours}${minutes}`; | |
| } | |
| var winterName = extractZone(winterOffset); | |
| var summerName = extractZone(summerOffset); | |
| #if ASSERTIONS | |
| assert(winterName); | |
| assert(summerName); | |
| assert(lengthBytesUTF8(winterName) <= {{{ cDefs.TZNAME_MAX }}}, `timezone name truncated to fit in TZNAME_MAX (${winterName})`); | |
| assert(lengthBytesUTF8(summerName) <= {{{ cDefs.TZNAME_MAX }}}, `timezone name truncated to fit in TZNAME_MAX (${summerName})`); | |
| #endif | |
| if (summerOffset < winterOffset) { | |
| // Northern hemisphere | |
| stringToUTF8(winterName, std_name, {{{ cDefs.TZNAME_MAX + 1 }}}); | |
| stringToUTF8(summerName, dst_name, {{{ cDefs.TZNAME_MAX + 1 }}}); | |
| } else { | |
| stringToUTF8(winterName, dst_name, {{{ cDefs.TZNAME_MAX + 1 }}}); | |
| stringToUTF8(summerName, std_name, {{{ cDefs.TZNAME_MAX + 1 }}}); | |
| } | |
| }, | |
| $MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], | |
| $MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], | |
| $MONTH_DAYS_REGULAR_CUMULATIVE: [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], | |
| $MONTH_DAYS_LEAP_CUMULATIVE: [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335], | |
| $isLeapYear: (year) => year%4 === 0 && (year%100 !== 0 || year%400 === 0), | |
| $ydayFromDate__deps: ['$isLeapYear', '$MONTH_DAYS_LEAP_CUMULATIVE', '$MONTH_DAYS_REGULAR_CUMULATIVE'], | |
| $ydayFromDate: (date) => { | |
| var leap = isLeapYear(date.getFullYear()); | |
| var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE); | |
| var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; // -1 since it's days since Jan 1 | |
| return yday; | |
| }, | |
| $arraySum: (array, index) => { | |
| var sum = 0; | |
| for (var i = 0; i <= index; sum += array[i++]) { | |
| // no-op | |
| } | |
| return sum; | |
| }, | |
| $addDays__deps: ['$isLeapYear', '$MONTH_DAYS_LEAP', '$MONTH_DAYS_REGULAR'], | |
| $addDays: (date, days) => { | |
| var newDate = new Date(date.getTime()); | |
| while (days > 0) { | |
| var leap = isLeapYear(newDate.getFullYear()); | |
| var currentMonth = newDate.getMonth(); | |
| var daysInCurrentMonth = (leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[currentMonth]; | |
| if (days > daysInCurrentMonth-newDate.getDate()) { | |
| // we spill over to next month | |
| days -= (daysInCurrentMonth-newDate.getDate()+1); | |
| newDate.setDate(1); | |
| if (currentMonth < 11) { | |
| newDate.setMonth(currentMonth+1) | |
| } else { | |
| newDate.setMonth(0); | |
| newDate.setFullYear(newDate.getFullYear()+1); | |
| } | |
| } else { | |
| // we stay in current month | |
| newDate.setDate(newDate.getDate()+days); | |
| return newDate; | |
| } | |
| } | |
| return newDate; | |
| }, | |
| strptime__deps: ['$isLeapYear', '$arraySum', '$addDays', '$MONTH_DAYS_REGULAR', '$MONTH_DAYS_LEAP', | |
| '$lengthBytesUTF8'], | |
| strptime: (buf, format, tm) => { | |
| // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); | |
| // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html | |
| var pattern = UTF8ToString(format); | |
| // escape special characters | |
| // TODO: not sure we really need to escape all of these in JS regexps | |
| var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.'; | |
| for (var i=0, ii=SPECIAL_CHARS.length; i<ii; ++i) { | |
| pattern = pattern.replace(new RegExp('\\'+SPECIAL_CHARS[i], 'g'), '\\'+SPECIAL_CHARS[i]); | |
| } | |
| // reduce number of matchers | |
| var EQUIVALENT_MATCHERS = { | |
| 'A': '%a', | |
| 'B': '%b', | |
| 'c': '%a %b %d %H:%M:%S %Y', | |
| 'D': '%m\\/%d\\/%y', | |
| 'e': '%d', | |
| 'F': '%Y-%m-%d', | |
| 'h': '%b', | |
| 'R': '%H\\:%M', | |
| 'r': '%I\\:%M\\:%S\\s%p', | |
| 'T': '%H\\:%M\\:%S', | |
| 'x': '%m\\/%d\\/(?:%y|%Y)', | |
| 'X': '%H\\:%M\\:%S' | |
| }; | |
| // TODO: take care of locale | |
| var DATE_PATTERNS = { | |
| /* weekday name */ 'a': '(?:Sun(?:day)?)|(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)', | |
| /* month name */ 'b': '(?:Jan(?:uary)?)|(?:Feb(?:ruary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|May|(?:Jun(?:e)?)|(?:Jul(?:y)?)|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)', | |
| /* century */ 'C': '\\d\\d', | |
| /* day of month */ 'd': '0[1-9]|[1-9](?!\\d)|1\\d|2\\d|30|31', | |
| /* hour (24hr) */ 'H': '\\d(?!\\d)|[0,1]\\d|20|21|22|23', | |
| /* hour (12hr) */ 'I': '\\d(?!\\d)|0\\d|10|11|12', | |
| /* day of year */ 'j': '00[1-9]|0?[1-9](?!\\d)|0?[1-9]\\d(?!\\d)|[1,2]\\d\\d|3[0-6]\\d', | |
| /* month */ 'm': '0[1-9]|[1-9](?!\\d)|10|11|12', | |
| /* minutes */ 'M': '0\\d|\\d(?!\\d)|[1-5]\\d', | |
| /* whitespace */ 'n': ' ', | |
| /* AM/PM */ 'p': 'AM|am|PM|pm|A\\.M\\.|a\\.m\\.|P\\.M\\.|p\\.m\\.', | |
| /* seconds */ 'S': '0\\d|\\d(?!\\d)|[1-5]\\d|60', | |
| /* week number */ 'U': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', | |
| /* week number */ 'W': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', | |
| /* weekday number */ 'w': '[0-6]', | |
| /* 2-digit year */ 'y': '\\d\\d', | |
| /* 4-digit year */ 'Y': '\\d\\d\\d\\d', | |
| /* whitespace */ 't': ' ', | |
| /* time zone */ 'z': 'Z|(?:[\\+\\-]\\d\\d:?(?:\\d\\d)?)' | |
| }; | |
| var MONTH_NUMBERS = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11}; | |
| var DAY_NUMBERS_SUN_FIRST = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6}; | |
| var DAY_NUMBERS_MON_FIRST = {MON: 0, TUE: 1, WED: 2, THU: 3, FRI: 4, SAT: 5, SUN: 6}; | |
| var capture = []; | |
| var pattern_out = pattern | |
| .replace(/%(.)/g, (m, c) => EQUIVALENT_MATCHERS[c] || m) | |
| .replace(/%(.)/g, (_, c) => { | |
| let pat = DATE_PATTERNS[c]; | |
| if (pat){ | |
| capture.push(c); | |
| return `(${pat})`; | |
| } else { | |
| return c; | |
| } | |
| }) | |
| .replace( // any number of space or tab characters match zero or more spaces | |
| /\s+/g,'\\s*' | |
| ); | |
| var matches = new RegExp('^'+pattern_out, "i").exec(UTF8ToString(buf)) | |
| function initDate() { | |
| function fixup(value, min, max) { | |
| return (typeof value != 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min); | |
| }; | |
| return { | |
| year: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900 , 1970, 9999), | |
| month: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mon, 'i32') }}}, 0, 11), | |
| day: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mday, 'i32') }}}, 1, 31), | |
| hour: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_hour, 'i32') }}}, 0, 23), | |
| min: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_min, 'i32') }}}, 0, 59), | |
| sec: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32') }}}, 0, 59), | |
| gmtoff: 0 | |
| }; | |
| }; | |
| if (matches) { | |
| var date = initDate(); | |
| var value; | |
| var getMatch = (symbol) => { | |
| var pos = capture.indexOf(symbol); | |
| // check if symbol appears in regexp | |
| if (pos >= 0) { | |
| // return matched value or null (falsy!) for non-matches | |
| return matches[pos+1]; | |
| } | |
| return; | |
| }; | |
| // seconds | |
| if ((value=getMatch('S'))) { | |
| date.sec = Number(value); | |
| } | |
| // minutes | |
| if ((value=getMatch('M'))) { | |
| date.min = Number(value); | |
| } | |
| // hours | |
| if ((value=getMatch('H'))) { | |
| // 24h clock | |
| date.hour = Number(value); | |
| } else if ((value = getMatch('I'))) { | |
| // AM/PM clock | |
| var hour = Number(value); | |
| if ((value=getMatch('p'))) { | |
| hour += value.toUpperCase()[0] === 'P' ? 12 : 0; | |
| } | |
| date.hour = hour; | |
| } | |
| // year | |
| if ((value=getMatch('Y'))) { | |
| // parse from four-digit year | |
| date.year = Number(value); | |
| } else if ((value=getMatch('y'))) { | |
| // parse from two-digit year... | |
| var year = Number(value); | |
| if ((value=getMatch('C'))) { | |
| // ...and century | |
| year += Number(value)*100; | |
| } else { | |
| // ...and rule-of-thumb | |
| year += year<69 ? 2000 : 1900; | |
| } | |
| date.year = year; | |
| } | |
| // month | |
| if ((value=getMatch('m'))) { | |
| // parse from month number | |
| date.month = Number(value)-1; | |
| } else if ((value=getMatch('b'))) { | |
| // parse from month name | |
| date.month = MONTH_NUMBERS[value.substring(0,3).toUpperCase()] || 0; | |
| // TODO: derive month from day in year+year, week number+day of week+year | |
| } | |
| // day | |
| if ((value=getMatch('d'))) { | |
| // get day of month directly | |
| date.day = Number(value); | |
| } else if ((value=getMatch('j'))) { | |
| // get day of month from day of year ... | |
| var day = Number(value); | |
| var leapYear = isLeapYear(date.year); | |
| for (var month=0; month<12; ++month) { | |
| var daysUntilMonth = arraySum(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, month-1); | |
| if (day<=daysUntilMonth+(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[month]) { | |
| date.day = day-daysUntilMonth; | |
| } | |
| } | |
| } else if ((value=getMatch('a'))) { | |
| // get day of month from weekday ... | |
| var weekDay = value.substring(0,3).toUpperCase(); | |
| if ((value=getMatch('U'))) { | |
| // ... and week number (Sunday being first day of week) | |
| // Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. | |
| // All days in a new year preceding the first Sunday are considered to be in week 0. | |
| var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay]; | |
| var weekNumber = Number(value); | |
| // January 1st | |
| var janFirst = new Date(date.year, 0, 1); | |
| var endDate; | |
| if (janFirst.getDay() === 0) { | |
| // Jan 1st is a Sunday, and, hence in the 1st CW | |
| endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); | |
| } else { | |
| // Jan 1st is not a Sunday, and, hence still in the 0th CW | |
| endDate = addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1)); | |
| } | |
| date.day = endDate.getDate(); | |
| date.month = endDate.getMonth(); | |
| } else if ((value=getMatch('W'))) { | |
| // ... and week number (Monday being first day of week) | |
| // Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. | |
| // All days in a new year preceding the first Monday are considered to be in week 0. | |
| var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay]; | |
| var weekNumber = Number(value); | |
| // January 1st | |
| var janFirst = new Date(date.year, 0, 1); | |
| var endDate; | |
| if (janFirst.getDay()===1) { | |
| // Jan 1st is a Monday, and, hence in the 1st CW | |
| endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); | |
| } else { | |
| // Jan 1st is not a Monday, and, hence still in the 0th CW | |
| endDate = addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1)); | |
| } | |
| date.day = endDate.getDate(); | |
| date.month = endDate.getMonth(); | |
| } | |
| } | |
| // time zone | |
| if ((value = getMatch('z'))) { | |
| // GMT offset as either 'Z' or +-HH:MM or +-HH or +-HHMM | |
| if (value.toLowerCase() === 'z'){ | |
| date.gmtoff = 0; | |
| } else { | |
| var match = value.match(/^((?:\-|\+)\d\d):?(\d\d)?/); | |
| date.gmtoff = match[1] * 3600; | |
| if (match[2]) { | |
| date.gmtoff += date.gmtoff >0 ? match[2] * 60 : -match[2] * 60 | |
| } | |
| } | |
| } | |
| /* | |
| tm_sec int seconds after the minute 0-61* | |
| tm_min int minutes after the hour 0-59 | |
| tm_hour int hours since midnight 0-23 | |
| tm_mday int day of the month 1-31 | |
| tm_mon int months since January 0-11 | |
| tm_year int years since 1900 | |
| tm_wday int days since Sunday 0-6 | |
| tm_yday int days since January 1 0-365 | |
| tm_isdst int Daylight Saving Time flag | |
| tm_gmtoff long offset from GMT (seconds) | |
| */ | |
| var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0); | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, 'arraySum(isLeapYear(fullDate.getFullYear()) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; | |
| {{{ makeSetValue('tm', C_STRUCTS.tm.tm_gmtoff, 'date.gmtoff', LONG_TYPE) }}}; | |
| // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F | |
| // TODO: not sure that intArrayFromString handles all unicode characters correctly | |
| return buf+lengthBytesUTF8(matches[0]); | |
| } | |
| return 0; | |
| }, | |
| strptime_l__deps: ['strptime'], | |
| strptime_l: (buf, format, tm, locale) => _strptime(buf, format, tm), // no locale support yet | |
| }); | |
Xet Storage Details
- Size:
- 23.3 kB
- Xet hash:
- 7027dadd6a84f9c8d3ab895af97298912a88168d486af8499af0f4d7f007c517
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.