Coverage Report

Created: 2026-08-13 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsDate.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2024  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
typedef struct sxDateTime {
41
  txNumber year;
42
  txNumber month;
43
  txNumber date;
44
  txNumber hours;
45
  txNumber minutes;
46
  txNumber seconds;
47
  txNumber milliseconds;
48
  txInteger day;
49
  txInteger offset;
50
  txNumber value;
51
} txDateTime;
52
53
static txSlot* fxNewDateInstance(txMachine* the);
54
55
static void fx_Date_aux(txMachine* the, txFlag secure);
56
static txInteger fx_Date_parse_number(txByte* theCharacter, txString* theString, txBoolean* overflow);
57
static txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString);
58
static txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* td, txBoolean utc, txSlot* slot);
59
static void fx_Date_prototype_set_aux(txMachine* the, txDateTime* td, txBoolean utc, txSlot* slot);
60
61
static txSlot* fxDateCheck(txMachine* the);
62
static txNumber fxDateClip(txNumber value);
63
static txNumber fxDateFullYear(txMachine* the, txSlot* slot);
64
static txNumber fxDateMerge(txDateTime* dt, txBoolean utc);
65
static txString fxDatePrint2Digits(txString p, txInteger value);  
66
static txString fxDatePrint3Digits(txString p, txInteger value);  
67
static txString fxDatePrint4Digits(txString p, txInteger value);  
68
static txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date); 
69
static txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date);
70
static txString fxDatePrintDay(txString p, txInteger day);  
71
static txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds); 
72
static txString fxDatePrintTimezone(txString p, txInteger offset);  
73
static txString fxDatePrintYear(txString p, txInteger value); 
74
static txInteger fxDateSimilarYear(txInteger year);
75
static void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt);
76
77
void fxBuildDate(txMachine* the)
78
31.3k
{
79
31.3k
  txSlot* slot;
80
31.3k
  mxPush(mxObjectPrototype);
81
31.3k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
31.3k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
31.3k
  mxDatePrototype = *the->stack;
130
31.3k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
31.3k
  mxDateConstructor = *the->stack;
132
31.3k
  slot = fxLastProperty(the, slot);
133
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
31.3k
  mxPop();
137
31.3k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
113k
{
141
113k
  txSlot* instance;
142
113k
  txSlot* property;
143
113k
  instance = fxNewObjectInstance(the);
144
113k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
113k
  property->kind = XS_DATE_KIND;
146
113k
  property->value.number = C_NAN;
147
113k
  return instance;
148
113k
}
149
150
void fx_Date(txMachine* the)
151
127k
{
152
127k
  fx_Date_aux(the, 0);
153
127k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
127k
{
157
127k
  txInteger c = mxArgc;
158
127k
  txDateTime dt;
159
127k
  txSlot* instance;
160
127k
  if (!mxHasTarget) {
161
14.2k
    char buffer[256];
162
14.2k
    txString p = buffer;
163
14.2k
    txDateTime dt;
164
14.2k
    if (secure)
165
0
      mxTypeError("secure mode");
166
14.2k
    mxResult->value.number = fxDateNow();
167
14.2k
    mxResult->kind = XS_NUMBER_KIND;
168
14.2k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
14.2k
    p = fxDatePrintDay(p, dt.day);
170
14.2k
    *p++ = ' ';
171
14.2k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
14.2k
    *p++ = ' ';
173
14.2k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
14.2k
    *p++ = ' ';
175
14.2k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
14.2k
    *p = 0;
177
14.2k
    fxCopyStringC(the, mxResult, buffer);
178
14.2k
    return;
179
14.2k
  }
180
113k
  mxPushSlot(mxTarget);
181
113k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
113k
  instance = fxNewDateInstance(the);
183
113k
  mxPullSlot(mxResult);
184
113k
  if (c > 1) {
185
21.0k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
21.0k
    dt.month = fxToNumber(the, mxArgv(1));
187
21.0k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
21.0k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
21.0k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
21.0k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
21.0k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
21.0k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
21.0k
    return;
194
21.0k
  }
195
91.9k
  if (c > 0) {
196
88.6k
    txSlot* slot = mxArgv(0);
197
88.6k
    if (slot->kind == XS_REFERENCE_KIND) {
198
1.15k
      txSlot* date = slot->value.reference;
199
1.15k
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
557
        instance->next->value.number = date->next->value.number;
201
557
        return;
202
557
      }
203
1.15k
    }
204
88.0k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
88.0k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
10.1k
      mxPushSlot(mxFunction);
207
10.1k
      mxDub();
208
10.1k
      mxGetID(mxID(_parse));
209
10.1k
      mxCall();
210
10.1k
      mxPushSlot(slot);
211
10.1k
      mxRunCount(1);
212
10.1k
      instance->next->value.number = the->stack->value.number;
213
10.1k
      mxPop();
214
10.1k
      return;
215
10.1k
    }
216
77.9k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
77.9k
    return;
218
88.0k
  }
219
3.31k
  if (secure)
220
0
    mxTypeError("secure mode");
221
3.31k
  instance->next->value.number = fxDateNow();
222
3.31k
}
223
224
void fx_Date_secure(txMachine* the)
225
0
{
226
0
  fx_Date_aux(the, 1);
227
0
}
228
229
void fx_Date_now(txMachine* the)
230
3
{
231
3
  mxResult->value.number = fxDateNow();
232
3
  mxResult->kind = XS_NUMBER_KIND;
233
3
}
234
235
void fx_Date_now_secure(txMachine* the)
236
0
{
237
0
  mxTypeError("secure mode");
238
0
}
239
240
txInteger fx_Date_parse_number(txByte* theCharacter, txString* theString, txBoolean* overflow)
241
572k
{
242
572k
  txByte c = *theCharacter;
243
572k
  txString p = *theString;
244
572k
  txInteger aResult = c - '0';
245
572k
  c = c_read8(p++);
246
1.06M
  while (('0' <= c) && (c <= '9')) {
247
489k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
489k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
458k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
36.3k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
489k
    c = c_read8(p++);
257
489k
  }
258
572k
  *theCharacter = c;
259
572k
  *theString = p;
260
572k
  return aResult;
261
572k
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
781
{
265
781
  txByte c = *theCharacter;
266
781
  txString p = *theString;
267
781
  txNumber fraction = 100;
268
781
  txNumber aResult = ((c - '0') * fraction);
269
781
  c = c_read8(p++);
270
1.33k
  while (('0' <= c) && (c <= '9')) {
271
552
    fraction /= 10;
272
552
    aResult = aResult + ((c - '0') * fraction);
273
552
    c = c_read8(p++);
274
552
  }
275
781
  *theCharacter = c;
276
781
  *theString = p;
277
781
  return (txInteger)c_trunc(aResult);
278
781
}
279
280
void fx_Date_parse(txMachine* the)
281
565k
{
282
2.79M
  #define mxDayCount 7
283
565k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
565k
    "monday", 
285
565k
    "tuesday", 
286
565k
    "wednesday", 
287
565k
    "thursday", 
288
565k
    "friday",
289
565k
    "saturday", 
290
565k
    "sunday"
291
565k
  };
292
4.24M
  #define mxMonthCount 12
293
565k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
565k
    "january",
295
565k
    "february",
296
565k
    "march",
297
565k
    "april",
298
565k
    "may",
299
565k
    "june",
300
565k
    "july",
301
565k
    "august",
302
565k
    "september",
303
565k
    "october",
304
565k
    "november",
305
565k
    "december"
306
565k
  };
307
3.86M
  #define mxZoneCount 11
308
565k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
565k
    "gmt", "ut", "utc",
310
565k
    "est", "edt",
311
565k
    "cst", "cdt",
312
565k
    "mst", "mdt",
313
565k
    "pst", "pdt"
314
565k
  };
315
565k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
565k
    0, 0, 0,
317
565k
    -5, -4,
318
565k
    -6, -5,
319
565k
    -7, -6,
320
565k
    -8, -7
321
565k
  };
322
  
323
565k
  txString aString;
324
565k
  txBoolean overflow = 0;
325
565k
  txDateTime dt;
326
565k
  txString p;
327
565k
  txString q;
328
565k
  txByte c;
329
565k
  char buffer[10];  /* base type should be the same as txString */
330
565k
  txInteger aComment;
331
565k
  txInteger aDelta;
332
565k
  txInteger aValue;
333
565k
  txSize aLength;
334
565k
  txInteger i;
335
565k
  txInteger yearSign = 1;
336
    
337
565k
  if (mxArgc < 1)
338
173
    goto fail;
339
565k
  aString = fxToString(the, mxArgv(0));
340
  
341
565k
  dt.seconds = -1;
342
565k
  dt.minutes = -1;
343
565k
  dt.hours = -1;
344
565k
  dt.date = -1;
345
565k
  dt.month = -1;
346
565k
  dt.year = -1;
347
565k
  dt.milliseconds = -1;
348
565k
  aComment = 0;
349
565k
  aDelta = -1;
350
351
565k
  c = c_read8(aString++);
352
3.69M
  while (c) {
353
3.68M
    if (c == '(') {
354
2.29k
      aComment++;
355
2.29k
      c = c_read8(aString++);
356
2.29k
      continue;
357
2.29k
    }
358
3.68M
    else if (c == ')') {
359
5.23k
      if (aComment) {
360
290
        aComment--;
361
290
        c = c_read8(aString++);
362
290
        continue;
363
290
      }
364
4.94k
      else
365
4.94k
        goto fail;
366
5.23k
    }
367
3.68M
    else if (aComment) {
368
18.7k
      c = c_read8(aString++);
369
18.7k
      continue;
370
18.7k
    }  
371
    
372
3.66M
    if ((c <= ' ') || (c == ',')) {
373
2.79M
      c = c_read8(aString++);
374
2.79M
      continue;
375
2.79M
    }
376
      
377
871k
    else if ((c == '-') | (c == '+')) {
378
19.9k
            txInteger aSign;
379
19.9k
      if (c == '-')  
380
18.6k
        aSign = -1;
381
1.35k
      else
382
1.35k
        aSign = 1;
383
19.9k
      c = c_read8(aString++);
384
19.9k
      if (('0' <= c) && (c <= '9')) {
385
18.6k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
18.6k
        if (c == '-') {
387
6.20k
          if (dt.year >= 0)
388
1.83k
            goto fail;
389
4.36k
          dt.year = aValue;
390
4.36k
          yearSign = aSign;
391
4.36k
          c = c_read8(aString++);
392
4.36k
          if (('0' <= c) && (c <= '9')) {
393
2.19k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
2.19k
            if (c == '-') {
395
1.02k
              c = c_read8(aString++);
396
1.02k
              if (('0' <= c) && (c <= '9'))
397
878
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
151
              else
399
151
                dt.date = 1;
400
1.02k
            }
401
2.19k
          }
402
2.17k
          else
403
2.17k
            dt.month = 0;
404
4.36k
        }
405
12.4k
        else {
406
12.4k
          if ((aDelta != 0) && (aDelta != -1))
407
547
            goto fail;
408
11.9k
          if (c == ':') {
409
2.26k
            aDelta = 60 * aValue;
410
2.26k
            c = c_read8(aString++);
411
2.26k
            if (('0' <= c) && (c <= '9')) {
412
991
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
991
            }
414
2.26k
          }
415
9.64k
          else {
416
9.64k
            if (aValue < 24)
417
6.47k
              aDelta = aValue * 60;
418
3.16k
            else
419
3.16k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
9.64k
          }
421
11.9k
          aDelta *= aSign;
422
11.9k
        }
423
18.6k
      }
424
1.32k
      else
425
1.32k
        goto fail;
426
19.9k
    }    
427
851k
    else if (('0' <= c) && (c <= '9')) {
428
289k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
289k
      if (c == ':') {
430
17.1k
        if (dt.hours >= 0) 
431
329
          goto fail;
432
16.7k
        dt.hours = aValue;  
433
16.7k
        c = c_read8(aString++);
434
16.7k
        if (('0' <= c) && (c <= '9')) {
435
9.92k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
9.92k
          if (c == ':') {
437
7.66k
            c = c_read8(aString++);
438
7.66k
            if (('0' <= c) && (c <= '9')) {
439
4.70k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
4.70k
              if (c == '.') {
441
1.40k
                c = c_read8(aString++);
442
1.40k
                if (('0' <= c) && (c <= '9')) {
443
781
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
781
                }
445
1.40k
              }
446
4.70k
            }
447
2.96k
            else
448
2.96k
              dt.seconds = 0;
449
7.66k
          }
450
9.92k
        }
451
6.85k
        else
452
6.85k
          dt.seconds = 0;
453
16.7k
      }
454
272k
      else if (c == '/') {
455
6.67k
        if (dt.year >= 0)
456
332
          goto fail;
457
6.33k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
6.33k
        c = c_read8(aString++);
459
6.33k
        if (('0' <= c) && (c <= '9')) {
460
5.18k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
5.18k
          if (c == '/') {
462
3.18k
            c = c_read8(aString++);
463
3.18k
            if (('0' <= c) && (c <= '9')) {
464
891
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
891
            }
466
2.29k
            else
467
2.29k
              dt.date = 1;
468
3.18k
          }
469
5.18k
        }
470
1.15k
        else
471
1.15k
          dt.month = 0;
472
6.33k
      }
473
266k
      else if (c == '-') {
474
240k
        if (dt.year >= 0)
475
981
          goto fail;
476
239k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
239k
        c = c_read8(aString++);
478
239k
        if (('0' <= c) && (c <= '9')) {
479
238k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
238k
          if (c == '-') {
481
2.82k
            c = c_read8(aString++);
482
2.82k
            if (('0' <= c) && (c <= '9'))
483
668
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
2.16k
            else
485
2.16k
              dt.date = 1;
486
2.82k
          }
487
238k
        }
488
693
        else
489
693
          dt.month = 0;
490
239k
      }
491
25.6k
      else {
492
25.6k
        if (aValue < 70) {
493
18.8k
          if (dt.date < 0)
494
13.3k
            dt.date = aValue;
495
5.48k
          else
496
5.48k
            goto fail;
497
18.8k
        }
498
6.83k
        else {
499
6.83k
          if (dt.year < 0)
500
6.32k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
517
          else
502
517
            goto fail;
503
6.83k
        }
504
25.6k
      }
505
289k
    }        
506
561k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
325k
      txSize cmpLength;
508
325k
      p = buffer;
509
325k
      q = p + sizeof(buffer) - 1;
510
874k
      do {
511
874k
        if (p == q) goto fail;
512
870k
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
870k
        c = c_read8(aString++);
514
870k
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
321k
      *p = 0;
516
321k
      aLength = mxPtrDiff(p - (txString)buffer);
517
321k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
321k
      if (c_strcmp("am", buffer) == 0) {
519
3.70k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
1.39k
          goto fail;
521
2.30k
        if (dt.hours == 12)
522
1.03k
          dt.hours = 0;
523
2.30k
        continue;
524
3.70k
      }
525
317k
      if (c_strcmp("pm", buffer) == 0) {
526
4.27k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
1.90k
          goto fail;
528
2.37k
        if (dt.hours != 12)
529
1.05k
          dt.hours += 12;
530
2.37k
        continue;
531
4.27k
      }
532
2.48M
      for (i = 0; i < mxDayCount; i++)
533
2.17M
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
6.62k
          break;
535
313k
      if (i < mxDayCount)
536
6.62k
        continue;
537
3.93M
      for (i = 0; i < mxMonthCount; i++)
538
3.63M
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
6.89k
          break;
540
306k
      if (i < mxMonthCount) {
541
6.89k
        if (dt.month < 0) {
542
6.63k
          dt.month = i;
543
6.63k
          continue;
544
6.63k
        }
545
256
        else
546
256
          goto fail;
547
6.89k
      }
548
3.56M
      for (i = 0; i < mxZoneCount; i++)
549
3.26M
        if (c_strcmp(gxZones[i], buffer) == 0)
550
3.22k
          break;
551
299k
      if (i < mxZoneCount) {
552
3.22k
        if (aDelta == -1) {
553
577
          aDelta = gxDeltas[i] * 60;
554
577
          continue;
555
577
        }
556
2.64k
        else
557
2.64k
          goto fail;
558
3.22k
      }
559
296k
      if (c_strcmp("t", buffer) == 0) {
560
1.77k
        if (dt.year < 0) 
561
184
          goto fail;
562
1.58k
        continue;
563
1.77k
      }
564
294k
      if (c_strcmp("z", buffer) == 0) {
565
4.82k
        if (dt.hours < 0) 
566
1.60k
          goto fail;
567
3.22k
        aDelta = 0;
568
3.22k
        continue;
569
4.82k
      }
570
289k
      goto fail;
571
294k
    }
572
236k
    else
573
236k
      goto fail;
574
3.66M
  }
575
10.7k
   if (overflow)
576
538
       goto fail;
577
10.2k
   if (dt.year < 0)
578
6.90k
       goto fail;
579
3.35k
  if ((yearSign < 0) && (dt.year == 0))
580
220
       goto fail;
581
3.13k
  if (dt.month < 0)
582
1.66k
    dt.month = 0;
583
3.13k
  if (dt.date < 0)
584
1.71k
    dt.date = 1;
585
3.13k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
911
    aDelta = 0;
587
3.13k
  if (dt.hours < 0)
588
917
    dt.hours = 0;
589
3.13k
  if (dt.minutes < 0)
590
1.61k
    dt.minutes = 0;
591
3.13k
    if (dt.seconds < 0)
592
1.84k
        dt.seconds = 0;
593
3.13k
    if (dt.milliseconds < 0)
594
2.98k
        dt.milliseconds = 0;
595
3.13k
    dt.year *= yearSign;
596
3.13k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
3.13k
  if (aDelta != -1)
598
2.33k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
3.13k
  mxResult->kind = XS_NUMBER_KIND;
600
3.13k
  return;
601
562k
fail:
602
562k
  mxResult->value.number = C_NAN;
603
562k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
562k
}
606
607
void fx_Date_UTC(txMachine* the)
608
188k
{
609
188k
  txInteger c = mxArgc;
610
188k
  txDateTime dt;
611
188k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
188k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
188k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
188k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
188k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
188k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
188k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
188k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
188k
    mxResult->kind = XS_NUMBER_KIND;
620
188k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
107k
{
624
107k
  txNumber number;
625
#if mxAliasInstance
626
  txSlot* instance = mxThis->value.reference;
627
  if (instance->ID) {
628
    txSlot* alias = the->aliasArray[instance->ID];
629
    if (alias) {
630
      instance = alias;
631
      slot = instance->next;
632
    }
633
  }
634
#endif
635
107k
  number = slot->value.number;
636
107k
  if (c_isnan(number)) {
637
82.0k
    mxResult->value.number = C_NAN;
638
82.0k
    mxResult->kind = XS_NUMBER_KIND;
639
82.0k
    dt->value = C_NAN;
640
82.0k
    return 0;
641
82.0k
  }
642
25.4k
  fxDateSplit(slot->value.number, utc, dt);
643
25.4k
  return 1;
644
107k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
474
{
648
474
  txNumber number = dt->value;
649
#if mxAliasInstance
650
  txSlot* instance = mxThis->value.reference;
651
  if (instance->ID) {
652
    txSlot* alias = the->aliasArray[instance->ID];
653
    if (alias)
654
      instance = alias;
655
    else
656
      instance = fxAliasInstance(the, instance);
657
    slot = instance->next;
658
  }
659
#endif
660
474
  if (c_isnan(number))
661
135
    return;
662
339
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
339
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
339
  mxResult->kind = XS_NUMBER_KIND;
666
339
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
71
{
670
71
  txDateTime dt;
671
71
  txSlot* slot = fxDateCheck(the);
672
71
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
22
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
22
    mxResult->kind = XS_INTEGER_KIND;
675
22
  }
676
71
}
677
678
void fx_Date_prototype_getSeconds(txMachine* the)
679
28
{
680
28
  txDateTime dt;
681
28
  txSlot* slot = fxDateCheck(the);
682
28
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
683
10
    mxResult->value.integer = (txInteger)dt.seconds;
684
10
    mxResult->kind = XS_INTEGER_KIND;
685
10
  }
686
28
}
687
688
void fx_Date_prototype_getMinutes(txMachine* the)
689
39
{
690
39
  txDateTime dt;
691
39
  txSlot* slot = fxDateCheck(the);
692
39
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
693
21
    mxResult->value.integer = (txInteger)dt.minutes;
694
21
    mxResult->kind = XS_INTEGER_KIND;
695
21
  }
696
39
}
697
698
void fx_Date_prototype_getHours(txMachine* the)
699
33
{
700
33
  txDateTime dt;
701
33
  txSlot* slot = fxDateCheck(the);
702
33
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
17
    mxResult->value.integer = (txInteger)dt.hours;
704
17
    mxResult->kind = XS_INTEGER_KIND;
705
17
  }
706
33
}
707
708
void fx_Date_prototype_getDay(txMachine* the)
709
76.0k
{
710
76.0k
  txDateTime dt;
711
76.0k
  txSlot* slot = fxDateCheck(the);
712
76.0k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
713
18
    mxResult->value.integer = dt.day;
714
18
    mxResult->kind = XS_INTEGER_KIND;
715
18
  }
716
76.0k
}
717
718
void fx_Date_prototype_getDate(txMachine* the)
719
46
{
720
46
  txDateTime dt;
721
46
  txSlot* slot = fxDateCheck(the);
722
46
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
723
21
    mxResult->value.integer = (txInteger)dt.date;
724
21
    mxResult->kind = XS_INTEGER_KIND;
725
21
  }
726
46
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
33
{
730
33
  txDateTime dt;
731
33
  txSlot* slot = fxDateCheck(the);
732
33
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
17
    mxResult->value.integer = (txInteger)dt.month;
734
17
    mxResult->kind = XS_INTEGER_KIND;
735
17
  }
736
33
}
737
738
void fx_Date_prototype_getYear(txMachine* the)
739
2
{
740
2
  txDateTime dt;
741
2
  txSlot* slot = fxDateCheck(the);
742
2
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
743
1
    mxResult->value.integer = (txInteger)dt.year - 1900;
744
1
    mxResult->kind = XS_INTEGER_KIND;
745
1
  }
746
2
}
747
748
void fx_Date_prototype_getFullYear(txMachine* the)
749
50
{
750
50
  txDateTime dt;
751
50
  txSlot* slot = fxDateCheck(the);
752
50
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
753
15
    mxResult->value.integer = (txInteger)dt.year;
754
15
    mxResult->kind = XS_INTEGER_KIND;
755
15
  }
756
50
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
68
{
760
68
  txDateTime dt;
761
68
  txSlot* slot = fxDateCheck(the);
762
68
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
763
9
    mxResult->value.integer = (txInteger)dt.milliseconds;
764
9
    mxResult->kind = XS_INTEGER_KIND;
765
9
  }
766
68
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
460
{
770
460
  txDateTime dt;
771
460
  txSlot* slot = fxDateCheck(the);
772
460
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
18
    mxResult->value.integer = (txInteger)dt.seconds;
774
18
    mxResult->kind = XS_INTEGER_KIND;
775
18
  }
776
460
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
37
{
780
37
  txDateTime dt;
781
37
  txSlot* slot = fxDateCheck(the);
782
37
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
783
16
    mxResult->value.integer = (txInteger)dt.minutes;
784
16
    mxResult->kind = XS_INTEGER_KIND;
785
16
  }
786
37
}
787
788
void fx_Date_prototype_getUTCHours(txMachine* the)
789
39
{
790
39
  txDateTime dt;
791
39
  txSlot* slot = fxDateCheck(the);
792
39
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
793
19
    mxResult->value.integer = (txInteger)dt.hours;
794
19
    mxResult->kind = XS_INTEGER_KIND;
795
19
  }
796
39
}
797
798
void fx_Date_prototype_getUTCDay(txMachine* the)
799
61
{
800
61
  txDateTime dt;
801
61
  txSlot* slot = fxDateCheck(the);
802
61
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
803
32
    mxResult->value.integer = dt.day;
804
32
    mxResult->kind = XS_INTEGER_KIND;
805
32
  }
806
61
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
46
{
810
46
  txDateTime dt;
811
46
  txSlot* slot = fxDateCheck(the);
812
46
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
24
    mxResult->value.integer = (txInteger)dt.date;
814
24
    mxResult->kind = XS_INTEGER_KIND;
815
24
  }
816
46
}
817
818
void fx_Date_prototype_getUTCMonth(txMachine* the)
819
39
{
820
39
  txDateTime dt;
821
39
  txSlot* slot = fxDateCheck(the);
822
39
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
823
15
    mxResult->value.integer = (txInteger)dt.month;
824
15
    mxResult->kind = XS_INTEGER_KIND;
825
15
  }
826
39
}
827
828
void fx_Date_prototype_getUTCFullYear(txMachine* the)
829
46
{
830
46
  txDateTime dt;
831
46
  txSlot* slot = fxDateCheck(the);
832
46
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
833
13
    mxResult->value.integer = (txInteger)dt.year;
834
13
    mxResult->kind = XS_INTEGER_KIND;
835
13
  }
836
46
}
837
838
void fx_Date_prototype_getTimezoneOffset(txMachine* the)
839
43
{
840
43
  txDateTime dt;
841
43
  txSlot* slot = fxDateCheck(the);
842
43
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
843
16
    mxResult->value.integer = 0 - dt.offset;
844
16
    mxResult->kind = XS_INTEGER_KIND;
845
16
  }
846
43
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
47
{
850
47
  txInteger c = mxArgc;
851
47
  txDateTime dt;
852
47
  txSlot* slot = fxDateCheck(the);
853
47
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
47
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
47
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
47
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
57
{
860
57
  txInteger c = mxArgc;
861
57
  txDateTime dt;
862
57
  txSlot* slot = fxDateCheck(the);
863
57
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
57
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
57
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
57
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
57
}
868
869
void fx_Date_prototype_setMinutes(txMachine* the)
870
1.88k
{
871
1.88k
  txInteger c = mxArgc;
872
1.88k
  txDateTime dt;
873
1.88k
  txSlot* slot = fxDateCheck(the);
874
1.88k
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
875
1.88k
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
876
1.88k
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
877
1.88k
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
878
1.88k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
879
1.88k
}
880
881
void fx_Date_prototype_setHours(txMachine* the)
882
77
{
883
77
  txInteger c = mxArgc;
884
77
  txDateTime dt;
885
77
  txSlot* slot = fxDateCheck(the);
886
77
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
77
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
77
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
77
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
77
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
77
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
77
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
60
{
896
60
  txInteger c = mxArgc;
897
60
  txDateTime dt;
898
60
  txSlot* slot = fxDateCheck(the);
899
60
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
60
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
60
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
60
}
903
904
void fx_Date_prototype_setMonth(txMachine* the)
905
344
{
906
344
  txInteger c = mxArgc;
907
344
  txDateTime dt;
908
344
  txSlot* slot = fxDateCheck(the);
909
344
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
344
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
344
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
344
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
344
}
914
915
void fx_Date_prototype_setYear(txMachine* the)
916
0
{
917
0
  txInteger c = mxArgc;
918
0
  txDateTime dt;
919
0
  txSlot* slot = fxDateCheck(the);
920
0
  if (c_isnan(slot->value.number)) {
921
0
    slot->value.number = 0;
922
0
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
923
0
  }
924
0
  else
925
0
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
926
0
  dt.year = (mxArgc > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
927
0
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
928
0
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
929
0
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
930
0
}
931
932
void fx_Date_prototype_setFullYear(txMachine* the)
933
1.88k
{
934
1.88k
  txInteger c = mxArgc;
935
1.88k
  txDateTime dt;
936
1.88k
  txSlot* slot = fxDateCheck(the);
937
1.88k
  if (c_isnan(slot->value.number)) {
938
8
    slot->value.number = 0;
939
8
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
940
8
  }
941
1.88k
  else
942
1.88k
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
943
1.88k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
1.88k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
1.88k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
1.88k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
1.88k
}
948
949
void fx_Date_prototype_setTime(txMachine* the)
950
78
{
951
78
  txSlot* slot = fxDateCheck(the);
952
78
  if (slot->flag & XS_DONT_SET_FLAG)
953
0
    mxTypeError("this: read-only Date instance");
954
78
  if (mxArgc < 1)
955
3
    slot->value.number = C_NAN;
956
75
  else {
957
75
    txNumber number = fxToNumber(the, mxArgv(0));
958
75
    int fpclass = c_fpclassify(number);
959
75
    if (fpclass != C_FP_NAN) {
960
33
      if (c_fabs(number) > 8.64e15)
961
1
        number = C_NAN;
962
32
      else
963
32
        number = c_trunc(number);
964
33
    }
965
75
    slot->value.number = number;
966
75
  }
967
78
  mxResult->value.number = slot->value.number;
968
78
  mxResult->kind = XS_NUMBER_KIND;
969
78
}
970
971
void fx_Date_prototype_setUTCMilliseconds(txMachine* the)
972
7
{
973
7
  txInteger c = mxArgc;
974
7
  txDateTime dt;
975
7
  txSlot* slot = fxDateCheck(the);
976
7
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
977
7
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
978
7
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
979
7
}
980
981
void fx_Date_prototype_setUTCSeconds(txMachine* the)
982
14
{
983
14
  txInteger c = mxArgc;
984
14
  txDateTime dt;
985
14
  txSlot* slot = fxDateCheck(the);
986
14
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
14
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
14
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
14
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
14
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
41
{
994
41
  txInteger c = mxArgc;
995
41
  txDateTime dt;
996
41
  txSlot* slot = fxDateCheck(the);
997
41
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
41
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
41
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
41
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
41
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
41
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
22
{
1006
22
  txInteger c = mxArgc;
1007
22
  txDateTime dt;
1008
22
  txSlot* slot = fxDateCheck(the);
1009
22
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
22
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
22
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
22
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
22
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
22
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
22
}
1016
1017
void fx_Date_prototype_setUTCDate(txMachine* the)
1018
4
{
1019
4
  txInteger c = mxArgc;
1020
4
  txDateTime dt;
1021
4
  txSlot* slot = fxDateCheck(the);
1022
4
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1023
4
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1024
4
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1025
4
}
1026
1027
void fx_Date_prototype_setUTCMonth(txMachine* the)
1028
1.89k
{
1029
1.89k
  txInteger c = mxArgc;
1030
1.89k
  txDateTime dt;
1031
1.89k
  txSlot* slot = fxDateCheck(the);
1032
1.89k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1033
1.89k
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1034
1.89k
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
1035
1.89k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1036
1.89k
}
1037
1038
void fx_Date_prototype_setUTCFullYear(txMachine* the)
1039
1.81k
{
1040
1.81k
  txInteger c = mxArgc;
1041
1.81k
  txDateTime dt;
1042
1.81k
  txSlot* slot = fxDateCheck(the);
1043
1.81k
  if (c_isnan(slot->value.number)) slot->value.number = 0;
1044
1.81k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1045
1.81k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1046
1.81k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
1047
1.81k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
1048
1.81k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1049
1.81k
}
1050
1051
void fx_Date_prototype_toDateString(txMachine* the)
1052
1.80k
{
1053
1.80k
  char buffer[256];
1054
1.80k
  txDateTime dt;
1055
1.80k
  txSlot* slot = fxDateCheck(the);
1056
1.80k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.10k
    txString p = buffer;
1058
1.10k
    p = fxDatePrintDay(p, dt.day);
1059
1.10k
    *p++ = ' ';
1060
1.10k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.10k
    *p = 0;
1062
1.10k
  }
1063
701
  else
1064
701
    c_strcpy(buffer, "Invalid Date");
1065
1.80k
  fxCopyStringC(the, mxResult, buffer);
1066
1.80k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
26
{
1070
26
  char buffer[256];
1071
26
  txDateTime dt;
1072
26
  txSlot* slot = fxDateCheck(the);
1073
26
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1074
20
    txString p = buffer;
1075
20
    p = fxDatePrintYear(p, (txInteger)dt.year);
1076
20
    *p++ = '-';
1077
20
    p = fxDatePrint2Digits(p, (txInteger)dt.month + 1);
1078
20
    *p++ = '-';
1079
20
    p = fxDatePrint2Digits(p, (txInteger)dt.date);
1080
20
    *p++ = 'T';
1081
20
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1082
20
    *p++ = '.';
1083
20
    p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds);
1084
20
    *p++ = 'Z';
1085
20
    *p = 0;
1086
20
  }
1087
6
  else
1088
6
        mxRangeError("Invalid Date");
1089
20
  fxCopyStringC(the, mxResult, buffer);
1090
20
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
14
{
1094
14
  fxToInstance(the, mxThis);
1095
14
  mxPushSlot(mxThis);
1096
14
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
14
  if ((the->stack->kind == XS_NUMBER_KIND) && !c_isfinite(the->stack->value.number)) {
1098
6
    mxPop();
1099
6
    mxResult->kind = XS_NULL_KIND;
1100
6
  }
1101
8
  else {   
1102
8
    mxPop();
1103
8
    mxPushSlot(mxThis);
1104
8
    mxDub();
1105
8
    mxGetID(mxID(_toISOString));
1106
8
    mxCall();
1107
8
    mxRunCount(0);
1108
8
    mxPullSlot(mxResult);
1109
8
  }
1110
14
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
30.2k
{
1114
30.2k
  if (mxIsReference(mxThis)) {
1115
30.2k
    txInteger hint = XS_NO_HINT;
1116
30.2k
    txInteger ids[2], i;
1117
30.2k
    if (mxArgc > 0) {
1118
30.2k
      txSlot* slot = mxArgv(0);
1119
30.2k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
30.2k
        if (!c_strcmp(slot->value.string, "default"))
1121
19.3k
          hint = XS_STRING_HINT;
1122
10.9k
        else if (!c_strcmp(slot->value.string, "number"))
1123
10.4k
          hint = XS_NUMBER_HINT;
1124
514
        else if (!c_strcmp(slot->value.string, "string"))
1125
503
          hint = XS_STRING_HINT;
1126
30.2k
      }
1127
30.2k
    }
1128
30.2k
    if (hint == XS_STRING_HINT) {
1129
19.8k
      ids[0] = mxID(_toString);
1130
19.8k
      ids[1] = mxID(_valueOf);
1131
19.8k
    }
1132
10.4k
    else if (hint == XS_NUMBER_HINT) {
1133
10.4k
      ids[0] = mxID(_valueOf);
1134
10.4k
      ids[1] = mxID(_toString);
1135
10.4k
    }
1136
25
    else
1137
25
        mxTypeError("invalid hint");
1138
30.2k
    for (i = 0; i < 2; i++) {
1139
30.2k
      mxPushSlot(mxThis);
1140
30.2k
      mxPushSlot(mxThis);
1141
30.2k
      mxGetID(ids[i]);
1142
30.2k
      if (fxIsCallable(the, the->stack)) {
1143
30.2k
        mxCall();
1144
30.2k
        mxRunCount(0);
1145
30.2k
        if (mxIsReference(the->stack))
1146
1
          mxPop();
1147
30.2k
        else {
1148
30.2k
          mxPullSlot(mxResult);
1149
30.2k
          return;
1150
30.2k
            }
1151
30.2k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
30.2k
    }
1157
2
    if (hint == XS_STRING_HINT)
1158
1
            mxTypeError("cannot coerce object to string");
1159
1
        else
1160
1
            mxTypeError("cannot coerce object to number");
1161
2
  }
1162
9
  else {
1163
9
        mxTypeError("invalid this");
1164
9
  }
1165
30.2k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
19.8k
{
1169
19.8k
  char buffer[256];
1170
19.8k
  txDateTime dt;
1171
19.8k
  txSlot* slot = fxDateCheck(the);
1172
19.8k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
17.0k
    txString p = buffer;
1174
17.0k
    p = fxDatePrintDay(p, dt.day);
1175
17.0k
    *p++ = ' ';
1176
17.0k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
17.0k
    *p++ = ' ';
1178
17.0k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
17.0k
    *p++ = ' ';
1180
17.0k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
17.0k
    *p = 0;
1182
17.0k
  }
1183
2.77k
  else
1184
2.77k
    c_strcpy(buffer, "Invalid Date");
1185
19.8k
  fxCopyStringC(the, mxResult, buffer);
1186
19.8k
}
1187
1188
void fx_Date_prototype_toTimeString(txMachine* the)
1189
2
{
1190
2
  char buffer[256];
1191
2
  txDateTime dt;
1192
2
  txSlot* slot = fxDateCheck(the);
1193
2
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1194
1
    txString p = buffer;
1195
1
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1196
1
    *p++ = ' ';
1197
1
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1198
1
    *p = 0;
1199
1
  }
1200
1
  else
1201
1
    c_strcpy(buffer, "Invalid Date");
1202
2
  fxCopyStringC(the, mxResult, buffer);
1203
2
}
1204
1205
void fx_Date_prototype_toUTCString(txMachine* the)
1206
1.32k
{
1207
1.32k
  char buffer[256];
1208
1.32k
  txDateTime dt;
1209
1.32k
  txSlot* slot = fxDateCheck(the);
1210
1.32k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
1.16k
    txString p = buffer;
1212
1.16k
    p = fxDatePrintDay(p, dt.day);
1213
1.16k
    *p++ = ',';
1214
1.16k
    *p++ = ' ';
1215
1.16k
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
1.16k
    *p++ = ' ';
1217
1.16k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
1.16k
    *p++ = ' ';
1219
1.16k
    *p++ = 'G';
1220
1.16k
    *p++ = 'M';
1221
1.16k
    *p++ = 'T';
1222
1.16k
    *p = 0;
1223
1.16k
  }
1224
160
  else
1225
160
    c_strcpy(buffer, "Invalid Date");
1226
1.32k
  fxCopyStringC(the, mxResult, buffer);
1227
1.32k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
10.8k
{
1231
10.8k
  txSlot* slot = fxDateCheck(the);
1232
10.8k
  mxResult->kind = XS_NUMBER_KIND;
1233
10.8k
  mxResult->value = slot->value;
1234
10.8k
}
1235
1236
// Thanks Google V8 for the years offset
1237
// Thanks Mozilla JS for the similar years
1238
1239
static const txString gxDayNames[] ICACHE_XS6RO2_ATTR = {
1240
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1241
};
1242
static const txString gxMonthNames[] ICACHE_XS6RO2_ATTR = {
1243
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1244
};
1245
static const txInteger gxCommonYearMonthsDays[12] ICACHE_XS6RO2_ATTR = { 
1246
  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 
1247
};
1248
static const txInteger gxLeapYearMonthsDays[12] ICACHE_XS6RO2_ATTR = { 
1249
  0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 
1250
};
1251
static const txInteger gxSimilarCommonYears[7] ICACHE_XS6RO2_ATTR = { 
1252
  1978, 1973, 1974, 1975, 1981, 1971, 1977 
1253
};
1254
static const txInteger gxSimilarLeapYears[7] ICACHE_XS6RO2_ATTR = { 
1255
  1984, 1996, 1980, 1992, 1976, 1988, 1972 
1256
};
1257
1258
479k
#define mx1YearDays 365
1259
359k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
239k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
119k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
403k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
409k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
94.6k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
374k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
119k
{
1271
119k
  txSlot* it = mxThis;
1272
119k
  if (it->kind == XS_REFERENCE_KIND) {
1273
118k
    txSlot* instance = it->value.reference;
1274
118k
    it = instance->next;
1275
118k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
118k
      return it;
1277
118k
  }
1278
119k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
119k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
398k
{
1284
398k
  if (!c_isfinite(value))
1285
76.2k
    value = C_NAN;
1286
322k
  else if (c_fabs(value) > 8.64e15)
1287
4.43k
    value = C_NAN;
1288
317k
  else {
1289
317k
    value = c_trunc(value);
1290
317k
    if (value == 0)
1291
2.24k
      value = 0;
1292
317k
  }
1293
398k
  return value; 
1294
398k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
209k
{
1298
209k
  txNumber result = fxToNumber(the, slot);
1299
209k
  if (c_isfinite(result)) {
1300
207k
    txInteger value = fxToInteger(the, slot);
1301
207k
    if ((0 <= value) && (value <= 99))
1302
194k
      result = 1900 + value;
1303
207k
  }
1304
209k
  return result;
1305
209k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
285k
{
1309
285k
  txNumber year, month;
1310
285k
  txInteger monthIndex;
1311
285k
  txBoolean leap;
1312
285k
  txNumber value;
1313
285k
  if ((!c_isfinite(dt->year))
1314
283k
  || (!c_isfinite(dt->month))
1315
283k
  || (!c_isfinite(dt->date))
1316
282k
  || (!c_isfinite(dt->hours))
1317
282k
  || (!c_isfinite(dt->minutes))
1318
282k
  || (!c_isfinite(dt->seconds))
1319
280k
  || (!c_isfinite(dt->milliseconds)))
1320
5.34k
    return C_NAN;
1321
279k
  year = c_trunc(dt->year);
1322
279k
  month = c_trunc(dt->month);
1323
279k
  year += c_floor(month / 12);
1324
279k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
279k
  if (monthIndex < 0)
1326
340
    monthIndex += 12;
1327
279k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
279k
  year += mxYearsOffset - 1;
1329
279k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
279k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
279k
  if (leap)
1332
17.8k
    value += gxLeapYearMonthsDays[monthIndex];
1333
261k
  else
1334
261k
    value += gxCommonYearMonthsDays[monthIndex];
1335
279k
  value += c_trunc(dt->date) - 1;
1336
279k
  value *= mxDayMilliseconds;
1337
279k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
279k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
279k
  value += c_trunc(dt->seconds) * 1000;
1340
279k
    value += c_trunc(dt->milliseconds);
1341
279k
  if (!utc) {
1342
20.2k
    txNumber former = value;
1343
20.2k
    txInteger similar;
1344
20.2k
    c_tm tm;
1345
20.2k
    c_time_t time;
1346
20.2k
    fxDateSplit(value, 1, dt);
1347
20.2k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
20.2k
    c_memset(&tm, 0, sizeof(c_tm));
1349
20.2k
    tm.tm_year = similar - 1900;
1350
20.2k
    tm.tm_mon = (txInteger)dt->month;
1351
20.2k
    tm.tm_mday = (txInteger)dt->date;
1352
20.2k
    tm.tm_hour = (txInteger)dt->hours;
1353
20.2k
    tm.tm_min = (txInteger)dt->minutes;
1354
20.2k
    tm.tm_sec = (txInteger)dt->seconds;
1355
20.2k
    tm.tm_isdst =-1;
1356
20.2k
    time = c_mktime(&tm);  
1357
20.2k
    if (time == -1)
1358
0
      value = NAN;
1359
20.2k
    else {
1360
20.2k
      value = (txNumber)time;
1361
20.2k
      value *= 1000;
1362
20.2k
      value += dt->milliseconds;
1363
20.2k
      if (similar != year) {
1364
20.2k
        dt->year = similar;
1365
20.2k
        value += former - fxDateMerge(dt, 1);
1366
20.2k
      }
1367
20.2k
    }
1368
20.2k
  }
1369
279k
  return fxDateClip(value);
1370
285k
}
1371
1372
txNumber fxDateNow()
1373
40.7k
{
1374
40.7k
  c_timeval tv;
1375
40.7k
  c_gettimeofday(&tv, NULL);
1376
40.7k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
40.7k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
227k
{
1381
227k
  *p++ = '0' + value / 10;
1382
227k
  *p++ = '0' + value % 10;
1383
227k
  return p;
1384
227k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
33.6k
{
1388
33.6k
  *p++ = '0' + value / 100;
1389
33.6k
  return fxDatePrint2Digits(p, value % 100);
1390
33.6k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
33.5k
{
1394
33.5k
  *p++ = '0' + value / 1000;
1395
33.5k
  return fxDatePrint3Digits(p, value % 1000);
1396
33.5k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
32.4k
{
1400
32.4k
  c_strcpy(p, gxMonthNames[month]);
1401
32.4k
  p += 3;
1402
32.4k
  *p++ = ' ';
1403
32.4k
  p = fxDatePrint2Digits(p, date);
1404
32.4k
  *p++ = ' ';
1405
32.4k
  p = fxDatePrintYear(p, year);
1406
32.4k
  return p;
1407
32.4k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
1.16k
{
1411
1.16k
  p = fxDatePrint2Digits(p, date);
1412
1.16k
  *p++ = ' ';
1413
1.16k
  c_strcpy(p, gxMonthNames[month]);
1414
1.16k
  p += 3;
1415
1.16k
  *p++ = ' ';
1416
1.16k
  p = fxDatePrintYear(p, year);
1417
1.16k
  return p;
1418
1.16k
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
33.5k
{
1422
33.5k
  c_strcpy(p, gxDayNames[day]);
1423
33.5k
  p += 3;
1424
33.5k
  return p;
1425
33.5k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
32.4k
{
1429
32.4k
  p = fxDatePrint2Digits(p, hours);
1430
32.4k
  *p++ = ':';
1431
32.4k
  p = fxDatePrint2Digits(p, minutes);
1432
32.4k
  *p++ = ':';
1433
32.4k
  p = fxDatePrint2Digits(p, seconds);
1434
32.4k
  return p;
1435
32.4k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
31.2k
{
1439
31.2k
  *p++ = 'G';
1440
31.2k
  *p++ = 'M';
1441
31.2k
  *p++ = 'T';
1442
31.2k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
31.2k
  else
1447
31.2k
    *p++ = '+';
1448
31.2k
  p = fxDatePrint2Digits(p, offset / 60);
1449
31.2k
  p = fxDatePrint2Digits(p, offset % 60);
1450
31.2k
  return p;
1451
31.2k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
33.5k
{
1455
33.5k
  if ((value < 0) || (9999 < value)) {
1456
3.89k
    if (value < 0) {
1457
2.93k
      *p++ = '-';
1458
2.93k
      value = -value;
1459
2.93k
    }
1460
961
    else
1461
961
      *p++ = '+';
1462
3.89k
    if (99999 < value) {
1463
1.37k
      *p++ = '0' + value / 100000;
1464
1.37k
      value %= 100000;
1465
1.37k
    }
1466
3.89k
    if (9999 < value) {
1467
2.80k
      *p++ = '0' + value / 10000;
1468
2.80k
      value %= 10000;
1469
2.80k
    }
1470
3.89k
  }
1471
33.5k
  return fxDatePrint4Digits(p, value);
1472
33.5k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
56.7k
{
1476
56.7k
  txInteger leap, day;
1477
56.7k
  if ((1970 <= year) && (year < 2038))
1478
22.0k
    return year;
1479
34.7k
  leap = mxIsLeapYear(year);
1480
34.7k
  year += mxYearsOffset - 1;
1481
34.7k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
34.7k
  day = (day + 4) % 7;
1483
34.7k
  if (day < 0)
1484
28.7k
    day += 7; 
1485
34.7k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
56.7k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
59.9k
{
1490
59.9k
  txInteger date, time, year, leap, month;
1491
59.9k
  const txInteger* monthsDays;
1492
59.9k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
59.9k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
59.9k
  if (time < 0) {
1495
3.38k
    date--;
1496
3.38k
    time += (txInteger)mxDayMilliseconds;
1497
3.38k
  }
1498
59.9k
  dt->offset = 0;
1499
59.9k
  dt->day = (date + 4) % 7;
1500
59.9k
  if (dt->day < 0)
1501
27.6k
    dt->day += 7; 
1502
59.9k
  dt->milliseconds = time % 1000;
1503
59.9k
  time /= 1000;
1504
59.9k
  dt->seconds = time % 60;
1505
59.9k
  time /= 60;
1506
59.9k
  dt->minutes = time % 60;
1507
59.9k
  time /= 60;
1508
59.9k
  dt->hours = time;
1509
59.9k
    date += mxYearDays(1970 + mxYearsOffset);
1510
59.9k
    year = 400 * (date / mx400YearsDays);
1511
59.9k
  date %= mx400YearsDays;
1512
59.9k
  date--;
1513
59.9k
  year += 100 * (date / mx100YearsDays);
1514
59.9k
  date %= mx100YearsDays;
1515
59.9k
  date++;
1516
59.9k
  year += 4 * (date / mx4YearsDays);
1517
59.9k
  date %= mx4YearsDays;
1518
59.9k
  date--;
1519
59.9k
  year += date / mx1YearDays;
1520
59.9k
    date %= mx1YearDays;
1521
59.9k
  year -= mxYearsOffset;
1522
59.9k
  leap = mxIsLeapYear(year);
1523
59.9k
    date += leap;
1524
59.9k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
371k
    for (month = 0; month < 11; month++) {
1526
367k
      if (date < monthsDays[month + 1])
1527
56.0k
        break;
1528
367k
    }
1529
59.9k
    date -= monthsDays[month];
1530
59.9k
  dt->date = date + 1;
1531
59.9k
  dt->month = month;
1532
59.9k
  dt->year = year;
1533
59.9k
  if (!utc) {
1534
36.4k
    txNumber former = value;
1535
36.4k
    txInteger similar;
1536
36.4k
    c_time_t time;
1537
36.4k
    c_tm tm;
1538
36.4k
    similar = fxDateSimilarYear(year);
1539
36.4k
    if (similar != year) {
1540
15.6k
      dt->year = similar;
1541
15.6k
      value = fxDateMerge(dt, 1);
1542
15.6k
    }
1543
36.4k
    time = (txInteger)c_floor(value / 1000.0);
1544
36.4k
    tm = *c_localtime(&time);
1545
36.4k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
36.4k
    dt->day = tm.tm_wday;
1547
36.4k
    dt->seconds = tm.tm_sec;
1548
36.4k
    dt->minutes = tm.tm_min;
1549
36.4k
    dt->hours = tm.tm_hour;
1550
36.4k
    dt->date = tm.tm_mday;
1551
36.4k
    dt->month = tm.tm_mon;
1552
36.4k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
36.4k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
36.4k
  }
1555
59.9k
  dt->value = value;
1556
59.9k
}
1557
1558
1559
1560