Coverage Report

Created: 2025-11-24 06:44

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-2025  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
33.8k
{
79
33.8k
  txSlot* slot;
80
33.8k
  mxPush(mxObjectPrototype);
81
33.8k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
33.8k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
33.8k
  mxDatePrototype = *the->stack;
130
33.8k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
33.8k
  mxDateConstructor = *the->stack;
132
33.8k
  slot = fxLastProperty(the, slot);
133
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
33.8k
  mxPop();
137
33.8k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
160k
{
141
160k
  txSlot* instance;
142
160k
  txSlot* property;
143
160k
  instance = fxNewObjectInstance(the);
144
160k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
160k
  property->kind = XS_DATE_KIND;
146
160k
  property->value.number = C_NAN;
147
160k
  return instance;
148
160k
}
149
150
void fx_Date(txMachine* the)
151
182k
{
152
182k
  fx_Date_aux(the, 0);
153
182k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
182k
{
157
182k
  txInteger c = mxArgc;
158
182k
  txDateTime dt;
159
182k
  txSlot* instance;
160
182k
  if (mxIsUndefined(mxTarget)) {
161
22.0k
    char buffer[256];
162
22.0k
    txString p = buffer;
163
22.0k
    txDateTime dt;
164
22.0k
    if (secure)
165
0
      mxTypeError("secure mode");
166
22.0k
    mxResult->value.number = fxDateNow();
167
22.0k
    mxResult->kind = XS_NUMBER_KIND;
168
22.0k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
22.0k
    p = fxDatePrintDay(p, dt.day);
170
22.0k
    *p++ = ' ';
171
22.0k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
22.0k
    *p++ = ' ';
173
22.0k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
22.0k
    *p++ = ' ';
175
22.0k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
22.0k
    *p = 0;
177
22.0k
    fxCopyStringC(the, mxResult, buffer);
178
22.0k
    return;
179
22.0k
  }
180
160k
  mxPushSlot(mxTarget);
181
160k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
160k
  instance = fxNewDateInstance(the);
183
160k
  mxPullSlot(mxResult);
184
160k
  if (c > 1) {
185
61.3k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
61.3k
    dt.month = fxToNumber(the, mxArgv(1));
187
61.3k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
61.3k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
61.3k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
61.3k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
61.3k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
61.3k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
61.3k
    return;
194
61.3k
  }
195
98.9k
  if (c > 0) {
196
96.5k
    txSlot* slot = mxArgv(0);
197
96.5k
    if (slot->kind == XS_REFERENCE_KIND) {
198
2.97k
      txSlot* date = slot->value.reference;
199
2.97k
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
597
        instance->next->value.number = date->next->value.number;
201
597
        return;
202
597
      }
203
2.97k
    }
204
95.9k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
95.9k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
17.9k
      mxPushSlot(mxFunction);
207
17.9k
      mxDub();
208
17.9k
      mxGetID(mxID(_parse));
209
17.9k
      mxCall();
210
17.9k
      mxPushSlot(slot);
211
17.9k
      mxRunCount(1);
212
17.9k
      instance->next->value.number = the->stack->value.number;
213
17.9k
      mxPop();
214
17.9k
      return;
215
17.9k
    }
216
78.0k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
78.0k
    return;
218
95.9k
  }
219
2.39k
  if (secure)
220
0
    mxTypeError("secure mode");
221
2.39k
  instance->next->value.number = fxDateNow();
222
2.39k
}
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
639k
{
242
639k
  txByte c = *theCharacter;
243
639k
  txString p = *theString;
244
639k
  txInteger aResult = c - '0';
245
639k
  c = c_read8(p++);
246
1.43M
  while (('0' <= c) && (c <= '9')) {
247
796k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
796k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
769k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
37.0k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
796k
    c = c_read8(p++);
257
796k
  }
258
639k
  *theCharacter = c;
259
639k
  *theString = p;
260
639k
  return aResult;
261
639k
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
3.16k
{
265
3.16k
  txByte c = *theCharacter;
266
3.16k
  txString p = *theString;
267
3.16k
  txNumber fraction = 100;
268
3.16k
  txNumber aResult = ((c - '0') * fraction);
269
3.16k
  c = c_read8(p++);
270
8.93k
  while (('0' <= c) && (c <= '9')) {
271
5.76k
    fraction /= 10;
272
5.76k
    aResult = aResult + ((c - '0') * fraction);
273
5.76k
    c = c_read8(p++);
274
5.76k
  }
275
3.16k
  *theCharacter = c;
276
3.16k
  *theString = p;
277
3.16k
  return (txInteger)c_trunc(aResult);
278
3.16k
}
279
280
void fx_Date_parse(txMachine* the)
281
551k
{
282
958k
  #define mxDayCount 7
283
551k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
551k
    "monday", 
285
551k
    "tuesday", 
286
551k
    "wednesday", 
287
551k
    "thursday", 
288
551k
    "friday",
289
551k
    "saturday", 
290
551k
    "sunday"
291
551k
  };
292
1.34M
  #define mxMonthCount 12
293
551k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
551k
    "january",
295
551k
    "february",
296
551k
    "march",
297
551k
    "april",
298
551k
    "may",
299
551k
    "june",
300
551k
    "july",
301
551k
    "august",
302
551k
    "september",
303
551k
    "october",
304
551k
    "november",
305
551k
    "december"
306
551k
  };
307
1.15M
  #define mxZoneCount 11
308
551k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
551k
    "gmt", "ut", "utc",
310
551k
    "est", "edt",
311
551k
    "cst", "cdt",
312
551k
    "mst", "mdt",
313
551k
    "pst", "pdt"
314
551k
  };
315
551k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
551k
    0, 0, 0,
317
551k
    -5, -4,
318
551k
    -6, -5,
319
551k
    -7, -6,
320
551k
    -8, -7
321
551k
  };
322
  
323
551k
  txString aString;
324
551k
  txBoolean overflow = 0;
325
551k
  txDateTime dt;
326
551k
  txString p;
327
551k
  txString q;
328
551k
  txByte c;
329
551k
  char buffer[10];  /* base type should be the same as txString */
330
551k
  txInteger aComment;
331
551k
  txInteger aDelta;
332
551k
  txInteger aValue;
333
551k
  txSize aLength;
334
551k
  txInteger i;
335
551k
  txInteger yearSign = 1;
336
    
337
551k
  if (mxArgc < 1)
338
1
    goto fail;
339
551k
  aString = fxToString(the, mxArgv(0));
340
  
341
551k
  dt.seconds = -1;
342
551k
  dt.minutes = -1;
343
551k
  dt.hours = -1;
344
551k
  dt.date = -1;
345
551k
  dt.month = -1;
346
551k
  dt.year = -1;
347
551k
  dt.milliseconds = -1;
348
551k
  aComment = 0;
349
551k
  aDelta = -1;
350
351
551k
  c = c_read8(aString++);
352
8.70M
  while (c) {
353
8.69M
    if (c == '(') {
354
1.93k
      aComment++;
355
1.93k
      c = c_read8(aString++);
356
1.93k
      continue;
357
1.93k
    }
358
8.68M
    else if (c == ')') {
359
10.3k
      if (aComment) {
360
1.06k
        aComment--;
361
1.06k
        c = c_read8(aString++);
362
1.06k
        continue;
363
1.06k
      }
364
9.28k
      else
365
9.28k
        goto fail;
366
10.3k
    }
367
8.67M
    else if (aComment) {
368
124k
      c = c_read8(aString++);
369
124k
      continue;
370
124k
    }  
371
    
372
8.55M
    if ((c <= ' ') || (c == ',')) {
373
7.63M
      c = c_read8(aString++);
374
7.63M
      continue;
375
7.63M
    }
376
      
377
923k
    else if ((c == '-') | (c == '+')) {
378
137k
            txInteger aSign;
379
137k
      if (c == '-')  
380
132k
        aSign = -1;
381
4.75k
      else
382
4.75k
        aSign = 1;
383
137k
      c = c_read8(aString++);
384
137k
      if (('0' <= c) && (c <= '9')) {
385
29.6k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
29.6k
        if (c == '-') {
387
10.0k
          if (dt.year >= 0)
388
1.18k
            goto fail;
389
8.84k
          dt.year = aValue;
390
8.84k
          yearSign = aSign;
391
8.84k
          c = c_read8(aString++);
392
8.84k
          if (('0' <= c) && (c <= '9')) {
393
7.12k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
7.12k
            if (c == '-') {
395
4.22k
              c = c_read8(aString++);
396
4.22k
              if (('0' <= c) && (c <= '9'))
397
3.35k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
878
              else
399
878
                dt.date = 1;
400
4.22k
            }
401
7.12k
          }
402
1.71k
          else
403
1.71k
            dt.month = 0;
404
8.84k
        }
405
19.6k
        else {
406
19.6k
          if ((aDelta != 0) && (aDelta != -1))
407
2.53k
            goto fail;
408
17.0k
          if (c == ':') {
409
3.44k
            aDelta = 60 * aValue;
410
3.44k
            c = c_read8(aString++);
411
3.44k
            if (('0' <= c) && (c <= '9')) {
412
678
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
678
            }
414
3.44k
          }
415
13.6k
          else {
416
13.6k
            if (aValue < 24)
417
8.43k
              aDelta = aValue * 60;
418
5.19k
            else
419
5.19k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
13.6k
          }
421
17.0k
          aDelta *= aSign;
422
17.0k
        }
423
29.6k
      }
424
107k
      else
425
107k
        goto fail;
426
137k
    }    
427
786k
    else if (('0' <= c) && (c <= '9')) {
428
308k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
308k
      if (c == ':') {
430
76.1k
        if (dt.hours >= 0) 
431
4.02k
          goto fail;
432
72.1k
        dt.hours = aValue;  
433
72.1k
        c = c_read8(aString++);
434
72.1k
        if (('0' <= c) && (c <= '9')) {
435
58.6k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
58.6k
          if (c == ':') {
437
54.9k
            c = c_read8(aString++);
438
54.9k
            if (('0' <= c) && (c <= '9')) {
439
52.1k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
52.1k
              if (c == '.') {
441
5.02k
                c = c_read8(aString++);
442
5.02k
                if (('0' <= c) && (c <= '9')) {
443
3.16k
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
3.16k
                }
445
5.02k
              }
446
52.1k
            }
447
2.83k
            else
448
2.83k
              dt.seconds = 0;
449
54.9k
          }
450
58.6k
        }
451
13.5k
        else
452
13.5k
          dt.seconds = 0;
453
72.1k
      }
454
232k
      else if (c == '/') {
455
4.68k
        if (dt.year >= 0)
456
212
          goto fail;
457
4.47k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
4.47k
        c = c_read8(aString++);
459
4.47k
        if (('0' <= c) && (c <= '9')) {
460
3.42k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
3.42k
          if (c == '/') {
462
1.48k
            c = c_read8(aString++);
463
1.48k
            if (('0' <= c) && (c <= '9')) {
464
1.19k
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
1.19k
            }
466
288
            else
467
288
              dt.date = 1;
468
1.48k
          }
469
3.42k
        }
470
1.04k
        else
471
1.04k
          dt.month = 0;
472
4.47k
      }
473
227k
      else if (c == '-') {
474
176k
        if (dt.year >= 0)
475
643
          goto fail;
476
175k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
175k
        c = c_read8(aString++);
478
175k
        if (('0' <= c) && (c <= '9')) {
479
173k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
173k
          if (c == '-') {
481
1.40k
            c = c_read8(aString++);
482
1.40k
            if (('0' <= c) && (c <= '9'))
483
1.07k
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
336
            else
485
336
              dt.date = 1;
486
1.40k
          }
487
173k
        }
488
2.64k
        else
489
2.64k
          dt.month = 0;
490
175k
      }
491
51.4k
      else {
492
51.4k
        if (aValue < 70) {
493
35.2k
          if (dt.date < 0)
494
26.6k
            dt.date = aValue;
495
8.60k
          else
496
8.60k
            goto fail;
497
35.2k
        }
498
16.1k
        else {
499
16.1k
          if (dt.year < 0)
500
13.1k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
2.93k
          else
502
2.93k
            goto fail;
503
16.1k
        }
504
51.4k
      }
505
308k
    }        
506
477k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
310k
      txSize cmpLength;
508
310k
      p = buffer;
509
310k
      q = p + sizeof(buffer) - 1;
510
2.11M
      do {
511
2.11M
        if (p == q) goto fail;
512
1.92M
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
1.92M
        c = c_read8(aString++);
514
1.92M
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
122k
      *p = 0;
516
122k
      aLength = mxPtrDiff(p - (txString)buffer);
517
122k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
122k
      if (c_strcmp("am", buffer) == 0) {
519
7.89k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
4.27k
          goto fail;
521
3.62k
        if (dt.hours == 12)
522
1.59k
          dt.hours = 0;
523
3.62k
        continue;
524
7.89k
      }
525
114k
      if (c_strcmp("pm", buffer) == 0) {
526
3.85k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
1.74k
          goto fail;
528
2.10k
        if (dt.hours != 12)
529
1.34k
          dt.hours += 12;
530
2.10k
        continue;
531
3.85k
      }
532
847k
      for (i = 0; i < mxDayCount; i++)
533
746k
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
9.92k
          break;
535
110k
      if (i < mxDayCount)
536
9.92k
        continue;
537
1.24M
      for (i = 0; i < mxMonthCount; i++)
538
1.15M
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
10.0k
          break;
540
100k
      if (i < mxMonthCount) {
541
10.0k
        if (dt.month < 0) {
542
9.93k
          dt.month = i;
543
9.93k
          continue;
544
9.93k
        }
545
127
        else
546
127
          goto fail;
547
10.0k
      }
548
1.06M
      for (i = 0; i < mxZoneCount; i++)
549
979k
        if (c_strcmp(gxZones[i], buffer) == 0)
550
2.08k
          break;
551
90.6k
      if (i < mxZoneCount) {
552
2.08k
        if (aDelta == -1) {
553
486
          aDelta = gxDeltas[i] * 60;
554
486
          continue;
555
486
        }
556
1.59k
        else
557
1.59k
          goto fail;
558
2.08k
      }
559
88.5k
      if (c_strcmp("t", buffer) == 0) {
560
45.5k
        if (dt.year < 0) 
561
300
          goto fail;
562
45.2k
        continue;
563
45.5k
      }
564
43.0k
      if (c_strcmp("z", buffer) == 0) {
565
10.4k
        if (dt.hours < 0) 
566
3.10k
          goto fail;
567
7.37k
        aDelta = 0;
568
7.37k
        continue;
569
10.4k
      }
570
32.5k
      goto fail;
571
43.0k
    }
572
167k
    else
573
167k
      goto fail;
574
8.55M
  }
575
15.1k
   if (overflow)
576
1.19k
       goto fail;
577
13.9k
   if (dt.year < 0)
578
3.91k
       goto fail;
579
10.0k
  if ((yearSign < 0) && (dt.year == 0))
580
280
       goto fail;
581
9.76k
  if (dt.month < 0)
582
4.35k
    dt.month = 0;
583
9.76k
  if (dt.date < 0)
584
6.56k
    dt.date = 1;
585
9.76k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
3.77k
    aDelta = 0;
587
9.76k
  if (dt.hours < 0)
588
3.90k
    dt.hours = 0;
589
9.76k
  if (dt.minutes < 0)
590
6.79k
    dt.minutes = 0;
591
9.76k
    if (dt.seconds < 0)
592
5.68k
        dt.seconds = 0;
593
9.76k
    if (dt.milliseconds < 0)
594
8.77k
        dt.milliseconds = 0;
595
9.76k
    dt.year *= yearSign;
596
9.76k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
9.76k
  if (aDelta != -1)
598
7.33k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
9.76k
  mxResult->kind = XS_NUMBER_KIND;
600
9.76k
  return;
601
541k
fail:
602
541k
  mxResult->value.number = C_NAN;
603
541k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
541k
}
606
607
void fx_Date_UTC(txMachine* the)
608
95.1k
{
609
95.1k
  txInteger c = mxArgc;
610
95.1k
  txDateTime dt;
611
95.1k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
95.1k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
95.1k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
95.1k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
95.1k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
95.1k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
95.1k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
95.1k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
95.1k
    mxResult->kind = XS_NUMBER_KIND;
620
95.1k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
147k
{
624
147k
  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
147k
  number = slot->value.number;
636
147k
  if (c_isnan(number)) {
637
101k
    mxResult->value.number = C_NAN;
638
101k
    mxResult->kind = XS_NUMBER_KIND;
639
101k
    dt->value = C_NAN;
640
101k
    return 0;
641
101k
  }
642
46.7k
  fxDateSplit(slot->value.number, utc, dt);
643
46.7k
  return 1;
644
147k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
393
{
648
393
  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
393
  if (c_isnan(number))
661
81
    return;
662
312
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
312
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
312
  mxResult->kind = XS_NUMBER_KIND;
666
312
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
56
{
670
56
  txDateTime dt;
671
56
  txSlot* slot = fxDateCheck(the);
672
56
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
14
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
14
    mxResult->kind = XS_INTEGER_KIND;
675
14
  }
676
56
}
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
9
    mxResult->value.integer = (txInteger)dt.seconds;
684
9
    mxResult->kind = XS_INTEGER_KIND;
685
9
  }
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
49
{
700
49
  txDateTime dt;
701
49
  txSlot* slot = fxDateCheck(the);
702
49
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
23
    mxResult->value.integer = (txInteger)dt.hours;
704
23
    mxResult->kind = XS_INTEGER_KIND;
705
23
  }
706
49
}
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
20
    mxResult->value.integer = dt.day;
714
20
    mxResult->kind = XS_INTEGER_KIND;
715
20
  }
716
76.0k
}
717
718
void fx_Date_prototype_getDate(txMachine* the)
719
73
{
720
73
  txDateTime dt;
721
73
  txSlot* slot = fxDateCheck(the);
722
73
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
723
18
    mxResult->value.integer = (txInteger)dt.date;
724
18
    mxResult->kind = XS_INTEGER_KIND;
725
18
  }
726
73
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
38
{
730
38
  txDateTime dt;
731
38
  txSlot* slot = fxDateCheck(the);
732
38
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
20
    mxResult->value.integer = (txInteger)dt.month;
734
20
    mxResult->kind = XS_INTEGER_KIND;
735
20
  }
736
38
}
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
30
{
750
30
  txDateTime dt;
751
30
  txSlot* slot = fxDateCheck(the);
752
30
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
753
12
    mxResult->value.integer = (txInteger)dt.year;
754
12
    mxResult->kind = XS_INTEGER_KIND;
755
12
  }
756
30
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
74
{
760
74
  txDateTime dt;
761
74
  txSlot* slot = fxDateCheck(the);
762
74
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
763
11
    mxResult->value.integer = (txInteger)dt.milliseconds;
764
11
    mxResult->kind = XS_INTEGER_KIND;
765
11
  }
766
74
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
604
{
770
604
  txDateTime dt;
771
604
  txSlot* slot = fxDateCheck(the);
772
604
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
20
    mxResult->value.integer = (txInteger)dt.seconds;
774
20
    mxResult->kind = XS_INTEGER_KIND;
775
20
  }
776
604
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
44
{
780
44
  txDateTime dt;
781
44
  txSlot* slot = fxDateCheck(the);
782
44
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
783
18
    mxResult->value.integer = (txInteger)dt.minutes;
784
18
    mxResult->kind = XS_INTEGER_KIND;
785
18
  }
786
44
}
787
788
void fx_Date_prototype_getUTCHours(txMachine* the)
789
41
{
790
41
  txDateTime dt;
791
41
  txSlot* slot = fxDateCheck(the);
792
41
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
793
18
    mxResult->value.integer = (txInteger)dt.hours;
794
18
    mxResult->kind = XS_INTEGER_KIND;
795
18
  }
796
41
}
797
798
void fx_Date_prototype_getUTCDay(txMachine* the)
799
59
{
800
59
  txDateTime dt;
801
59
  txSlot* slot = fxDateCheck(the);
802
59
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
803
31
    mxResult->value.integer = dt.day;
804
31
    mxResult->kind = XS_INTEGER_KIND;
805
31
  }
806
59
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
54
{
810
54
  txDateTime dt;
811
54
  txSlot* slot = fxDateCheck(the);
812
54
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
23
    mxResult->value.integer = (txInteger)dt.date;
814
23
    mxResult->kind = XS_INTEGER_KIND;
815
23
  }
816
54
}
817
818
void fx_Date_prototype_getUTCMonth(txMachine* the)
819
42
{
820
42
  txDateTime dt;
821
42
  txSlot* slot = fxDateCheck(the);
822
42
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
823
18
    mxResult->value.integer = (txInteger)dt.month;
824
18
    mxResult->kind = XS_INTEGER_KIND;
825
18
  }
826
42
}
827
828
void fx_Date_prototype_getUTCFullYear(txMachine* the)
829
47
{
830
47
  txDateTime dt;
831
47
  txSlot* slot = fxDateCheck(the);
832
47
  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
47
}
837
838
void fx_Date_prototype_getTimezoneOffset(txMachine* the)
839
52
{
840
52
  txDateTime dt;
841
52
  txSlot* slot = fxDateCheck(the);
842
52
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
843
13
    mxResult->value.integer = 0 - dt.offset;
844
13
    mxResult->kind = XS_INTEGER_KIND;
845
13
  }
846
52
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
44
{
850
44
  txInteger c = mxArgc;
851
44
  txDateTime dt;
852
44
  txSlot* slot = fxDateCheck(the);
853
44
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
44
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
44
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
44
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
63
{
860
63
  txInteger c = mxArgc;
861
63
  txDateTime dt;
862
63
  txSlot* slot = fxDateCheck(the);
863
63
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
63
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
63
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
63
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
63
}
868
869
void fx_Date_prototype_setMinutes(txMachine* the)
870
63
{
871
63
  txInteger c = mxArgc;
872
63
  txDateTime dt;
873
63
  txSlot* slot = fxDateCheck(the);
874
63
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
875
63
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
876
63
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
877
63
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
878
63
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
879
63
}
880
881
void fx_Date_prototype_setHours(txMachine* the)
882
71
{
883
71
  txInteger c = mxArgc;
884
71
  txDateTime dt;
885
71
  txSlot* slot = fxDateCheck(the);
886
71
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
71
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
71
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
71
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
71
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
71
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
71
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
38
{
896
38
  txInteger c = mxArgc;
897
38
  txDateTime dt;
898
38
  txSlot* slot = fxDateCheck(the);
899
38
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
38
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
38
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
38
}
903
904
void fx_Date_prototype_setMonth(txMachine* the)
905
60
{
906
60
  txInteger c = mxArgc;
907
60
  txDateTime dt;
908
60
  txSlot* slot = fxDateCheck(the);
909
60
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
910
60
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
911
60
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
912
60
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
913
60
}
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.90k
{
934
1.90k
  txInteger c = mxArgc;
935
1.90k
  txDateTime dt;
936
1.90k
  txSlot* slot = fxDateCheck(the);
937
1.90k
  if (c_isnan(slot->value.number)) {
938
9
    slot->value.number = 0;
939
9
    fx_Date_prototype_get_aux(the, &dt, 1, slot);
940
9
  }
941
1.89k
  else
942
1.89k
    fx_Date_prototype_get_aux(the, &dt, 0, slot);
943
1.90k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
1.90k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
1.90k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
1.90k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
1.90k
}
948
949
void fx_Date_prototype_setTime(txMachine* the)
950
69
{
951
69
  txSlot* slot = fxDateCheck(the);
952
69
  if (slot->flag & XS_DONT_SET_FLAG)
953
0
    mxTypeError("this: read-only Date instance");
954
69
  if (mxArgc < 1)
955
2
    slot->value.number = C_NAN;
956
67
  else {
957
67
    txNumber number = fxToNumber(the, mxArgv(0));
958
67
    int fpclass = c_fpclassify(number);
959
67
    if (fpclass != C_FP_NAN) {
960
27
      if (c_fabs(number) > 8.64e15)
961
1
        number = C_NAN;
962
26
      else
963
26
        number = c_trunc(number);
964
27
    }
965
67
    slot->value.number = number;
966
67
  }
967
69
  mxResult->value.number = slot->value.number;
968
69
  mxResult->kind = XS_NUMBER_KIND;
969
69
}
970
971
void fx_Date_prototype_setUTCMilliseconds(txMachine* the)
972
13
{
973
13
  txInteger c = mxArgc;
974
13
  txDateTime dt;
975
13
  txSlot* slot = fxDateCheck(the);
976
13
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
977
13
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
978
13
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
979
13
}
980
981
void fx_Date_prototype_setUTCSeconds(txMachine* the)
982
12
{
983
12
  txInteger c = mxArgc;
984
12
  txDateTime dt;
985
12
  txSlot* slot = fxDateCheck(the);
986
12
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
12
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
12
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
12
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
12
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
40
{
994
40
  txInteger c = mxArgc;
995
40
  txDateTime dt;
996
40
  txSlot* slot = fxDateCheck(the);
997
40
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
40
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
40
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
40
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
40
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
40
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
28
{
1006
28
  txInteger c = mxArgc;
1007
28
  txDateTime dt;
1008
28
  txSlot* slot = fxDateCheck(the);
1009
28
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
28
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
28
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
28
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
28
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
28
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
28
}
1016
1017
void fx_Date_prototype_setUTCDate(txMachine* the)
1018
3
{
1019
3
  txInteger c = mxArgc;
1020
3
  txDateTime dt;
1021
3
  txSlot* slot = fxDateCheck(the);
1022
3
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1023
3
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1024
3
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1025
3
}
1026
1027
void fx_Date_prototype_setUTCMonth(txMachine* the)
1028
1.85k
{
1029
1.85k
  txInteger c = mxArgc;
1030
1.85k
  txDateTime dt;
1031
1.85k
  txSlot* slot = fxDateCheck(the);
1032
1.85k
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1033
1.85k
  dt.month = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1034
1.85k
  if (c > 1) dt.date = fxToNumber(the, mxArgv(1));
1035
1.85k
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1036
1.85k
}
1037
1038
void fx_Date_prototype_setUTCFullYear(txMachine* the)
1039
7
{
1040
7
  txInteger c = mxArgc;
1041
7
  txDateTime dt;
1042
7
  txSlot* slot = fxDateCheck(the);
1043
7
  if (c_isnan(slot->value.number)) slot->value.number = 0;
1044
7
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1045
7
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1046
7
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
1047
7
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
1048
7
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1049
7
}
1050
1051
void fx_Date_prototype_toDateString(txMachine* the)
1052
4.61k
{
1053
4.61k
  char buffer[256];
1054
4.61k
  txDateTime dt;
1055
4.61k
  txSlot* slot = fxDateCheck(the);
1056
4.61k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.84k
    txString p = buffer;
1058
1.84k
    p = fxDatePrintDay(p, dt.day);
1059
1.84k
    *p++ = ' ';
1060
1.84k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.84k
    *p = 0;
1062
1.84k
  }
1063
2.76k
  else
1064
2.76k
    c_strcpy(buffer, "Invalid Date");
1065
4.61k
  fxCopyStringC(the, mxResult, buffer);
1066
4.61k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
22
{
1070
22
  char buffer[256];
1071
22
  txDateTime dt;
1072
22
  txSlot* slot = fxDateCheck(the);
1073
22
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1074
15
    txString p = buffer;
1075
15
    p = fxDatePrintYear(p, (txInteger)dt.year);
1076
15
    *p++ = '-';
1077
15
    p = fxDatePrint2Digits(p, (txInteger)dt.month + 1);
1078
15
    *p++ = '-';
1079
15
    p = fxDatePrint2Digits(p, (txInteger)dt.date);
1080
15
    *p++ = 'T';
1081
15
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1082
15
    *p++ = '.';
1083
15
    p = fxDatePrint3Digits(p, (txInteger)dt.milliseconds);
1084
15
    *p++ = 'Z';
1085
15
    *p = 0;
1086
15
  }
1087
7
  else
1088
7
        mxRangeError("Invalid Date");
1089
15
  fxCopyStringC(the, mxResult, buffer);
1090
15
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
11
{
1094
11
  fxToInstance(the, mxThis);
1095
11
  mxPushSlot(mxThis);
1096
11
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
11
  if ((the->stack->kind == XS_NUMBER_KIND) && !c_isfinite(the->stack->value.number)) {
1098
3
    mxPop();
1099
3
    mxResult->kind = XS_NULL_KIND;
1100
3
  }
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
11
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
74.1k
{
1114
74.1k
  if (mxIsReference(mxThis)) {
1115
74.1k
    txInteger hint = XS_NO_HINT;
1116
74.1k
    txInteger ids[2], i;
1117
74.1k
    if (mxArgc > 0) {
1118
74.1k
      txSlot* slot = mxArgv(0);
1119
74.1k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
74.0k
        if (!c_strcmp(slot->value.string, "default"))
1121
60.2k
          hint = XS_STRING_HINT;
1122
13.8k
        else if (!c_strcmp(slot->value.string, "number"))
1123
13.7k
          hint = XS_NUMBER_HINT;
1124
83
        else if (!c_strcmp(slot->value.string, "string"))
1125
73
          hint = XS_STRING_HINT;
1126
74.0k
      }
1127
74.1k
    }
1128
74.1k
    if (hint == XS_STRING_HINT) {
1129
60.3k
      ids[0] = mxID(_toString);
1130
60.3k
      ids[1] = mxID(_valueOf);
1131
60.3k
    }
1132
13.7k
    else if (hint == XS_NUMBER_HINT) {
1133
13.7k
      ids[0] = mxID(_valueOf);
1134
13.7k
      ids[1] = mxID(_toString);
1135
13.7k
    }
1136
25
    else
1137
25
        mxTypeError("invalid hint");
1138
74.0k
    for (i = 0; i < 2; i++) {
1139
74.0k
      mxPushSlot(mxThis);
1140
74.0k
      mxPushSlot(mxThis);
1141
74.0k
      mxGetID(ids[i]);
1142
74.0k
      if (fxIsCallable(the, the->stack)) {
1143
74.0k
        mxCall();
1144
74.0k
        mxRunCount(0);
1145
74.0k
        if (mxIsReference(the->stack))
1146
2
          mxPop();
1147
74.0k
        else {
1148
74.0k
          mxPullSlot(mxResult);
1149
74.0k
          return;
1150
74.0k
            }
1151
74.0k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
74.0k
    }
1157
3
    if (hint == XS_STRING_HINT)
1158
2
            mxTypeError("cannot coerce object to string");
1159
1
        else
1160
1
            mxTypeError("cannot coerce object to number");
1161
3
  }
1162
11
  else {
1163
11
        mxTypeError("invalid this");
1164
11
  }
1165
74.1k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
60.3k
{
1169
60.3k
  char buffer[256];
1170
60.3k
  txDateTime dt;
1171
60.3k
  txSlot* slot = fxDateCheck(the);
1172
60.3k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
40.8k
    txString p = buffer;
1174
40.8k
    p = fxDatePrintDay(p, dt.day);
1175
40.8k
    *p++ = ' ';
1176
40.8k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
40.8k
    *p++ = ' ';
1178
40.8k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
40.8k
    *p++ = ' ';
1180
40.8k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
40.8k
    *p = 0;
1182
40.8k
  }
1183
19.5k
  else
1184
19.5k
    c_strcpy(buffer, "Invalid Date");
1185
60.3k
  fxCopyStringC(the, mxResult, buffer);
1186
60.3k
}
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.99k
{
1207
1.99k
  char buffer[256];
1208
1.99k
  txDateTime dt;
1209
1.99k
  txSlot* slot = fxDateCheck(the);
1210
1.99k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
1.58k
    txString p = buffer;
1212
1.58k
    p = fxDatePrintDay(p, dt.day);
1213
1.58k
    *p++ = ',';
1214
1.58k
    *p++ = ' ';
1215
1.58k
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
1.58k
    *p++ = ' ';
1217
1.58k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
1.58k
    *p++ = ' ';
1219
1.58k
    *p++ = 'G';
1220
1.58k
    *p++ = 'M';
1221
1.58k
    *p++ = 'T';
1222
1.58k
    *p = 0;
1223
1.58k
  }
1224
409
  else
1225
409
    c_strcpy(buffer, "Invalid Date");
1226
1.99k
  fxCopyStringC(the, mxResult, buffer);
1227
1.99k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
14.1k
{
1231
14.1k
  txSlot* slot = fxDateCheck(the);
1232
14.1k
  mxResult->kind = XS_NUMBER_KIND;
1233
14.1k
  mxResult->value = slot->value;
1234
14.1k
}
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
925k
#define mx1YearDays 365
1259
694k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
462k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
231k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
494k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
535k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
194k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
456k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
162k
{
1271
162k
  txSlot* it = mxThis;
1272
162k
  if (it->kind == XS_REFERENCE_KIND) {
1273
162k
    txSlot* instance = it->value.reference;
1274
162k
    it = instance->next;
1275
162k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
162k
      return it;
1277
162k
  }
1278
162k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
162k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
548k
{
1284
548k
  if (!c_isfinite(value))
1285
77.5k
    value = C_NAN;
1286
471k
  else if (c_fabs(value) > 8.64e15)
1287
54.2k
    value = C_NAN;
1288
417k
  else {
1289
417k
    value = c_trunc(value);
1290
417k
    if (value == 0)
1291
2.68k
      value = 0;
1292
417k
  }
1293
548k
  return value; 
1294
548k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
155k
{
1298
155k
  txNumber result = fxToNumber(the, slot);
1299
155k
  if (c_isfinite(result)) {
1300
138k
    txInteger value = fxToInteger(the, slot);
1301
138k
    if ((0 <= value) && (value <= 99))
1302
43.4k
      result = 1900 + value;
1303
138k
  }
1304
155k
  return result;
1305
155k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
317k
{
1309
317k
  txNumber year, month;
1310
317k
  txInteger monthIndex;
1311
317k
  txBoolean leap;
1312
317k
  txNumber value;
1313
317k
  if ((!c_isfinite(dt->year))
1314
299k
  || (!c_isfinite(dt->month))
1315
299k
  || (!c_isfinite(dt->date))
1316
299k
  || (!c_isfinite(dt->hours))
1317
263k
  || (!c_isfinite(dt->minutes))
1318
263k
  || (!c_isfinite(dt->seconds))
1319
261k
  || (!c_isfinite(dt->milliseconds)))
1320
55.6k
    return C_NAN;
1321
261k
  year = c_trunc(dt->year);
1322
261k
  month = c_trunc(dt->month);
1323
261k
  year += c_floor(month / 12);
1324
261k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
261k
  if (monthIndex < 0)
1326
668
    monthIndex += 12;
1327
261k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
261k
  year += mxYearsOffset - 1;
1329
261k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
261k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
261k
  if (leap)
1332
33.1k
    value += gxLeapYearMonthsDays[monthIndex];
1333
228k
  else
1334
228k
    value += gxCommonYearMonthsDays[monthIndex];
1335
261k
  value += c_trunc(dt->date) - 1;
1336
261k
  value *= mxDayMilliseconds;
1337
261k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
261k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
261k
  value += c_trunc(dt->seconds) * 1000;
1340
261k
    value += c_trunc(dt->milliseconds);
1341
261k
  if (!utc) {
1342
46.8k
    txNumber former = value;
1343
46.8k
    txInteger similar;
1344
46.8k
    c_tm tm;
1345
46.8k
    c_time_t time;
1346
46.8k
    fxDateSplit(value, 1, dt);
1347
46.8k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
46.8k
    c_memset(&tm, 0, sizeof(c_tm));
1349
46.8k
    tm.tm_year = similar - 1900;
1350
46.8k
    tm.tm_mon = (txInteger)dt->month;
1351
46.8k
    tm.tm_mday = (txInteger)dt->date;
1352
46.8k
    tm.tm_hour = (txInteger)dt->hours;
1353
46.8k
    tm.tm_min = (txInteger)dt->minutes;
1354
46.8k
    tm.tm_sec = (txInteger)dt->seconds;
1355
46.8k
    tm.tm_isdst =-1;
1356
46.8k
    time = c_mktime(&tm);  
1357
46.8k
    if (time == -1)
1358
0
      value = NAN;
1359
46.8k
    else {
1360
46.8k
      value = (txNumber)time;
1361
46.8k
      value *= 1000;
1362
46.8k
      value += dt->milliseconds;
1363
46.8k
      if (similar != year) {
1364
46.8k
        dt->year = similar;
1365
46.8k
        value += former - fxDateMerge(dt, 1);
1366
46.8k
      }
1367
46.8k
    }
1368
46.8k
  }
1369
261k
  return fxDateClip(value);
1370
317k
}
1371
1372
txNumber fxDateNow()
1373
209k
{
1374
209k
  c_timeval tv;
1375
209k
  c_gettimeofday(&tv, NULL);
1376
209k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
209k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
452k
{
1381
452k
  *p++ = '0' + value / 10;
1382
452k
  *p++ = '0' + value % 10;
1383
452k
  return p;
1384
452k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
66.3k
{
1388
66.3k
  *p++ = '0' + value / 100;
1389
66.3k
  return fxDatePrint2Digits(p, value % 100);
1390
66.3k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
66.3k
{
1394
66.3k
  *p++ = '0' + value / 1000;
1395
66.3k
  return fxDatePrint3Digits(p, value % 1000);
1396
66.3k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
64.7k
{
1400
64.7k
  c_strcpy(p, gxMonthNames[month]);
1401
64.7k
  p += 3;
1402
64.7k
  *p++ = ' ';
1403
64.7k
  p = fxDatePrint2Digits(p, date);
1404
64.7k
  *p++ = ' ';
1405
64.7k
  p = fxDatePrintYear(p, year);
1406
64.7k
  return p;
1407
64.7k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
1.58k
{
1411
1.58k
  p = fxDatePrint2Digits(p, date);
1412
1.58k
  *p++ = ' ';
1413
1.58k
  c_strcpy(p, gxMonthNames[month]);
1414
1.58k
  p += 3;
1415
1.58k
  *p++ = ' ';
1416
1.58k
  p = fxDatePrintYear(p, year);
1417
1.58k
  return p;
1418
1.58k
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
66.3k
{
1422
66.3k
  c_strcpy(p, gxDayNames[day]);
1423
66.3k
  p += 3;
1424
66.3k
  return p;
1425
66.3k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
64.4k
{
1429
64.4k
  p = fxDatePrint2Digits(p, hours);
1430
64.4k
  *p++ = ':';
1431
64.4k
  p = fxDatePrint2Digits(p, minutes);
1432
64.4k
  *p++ = ':';
1433
64.4k
  p = fxDatePrint2Digits(p, seconds);
1434
64.4k
  return p;
1435
64.4k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
62.8k
{
1439
62.8k
  *p++ = 'G';
1440
62.8k
  *p++ = 'M';
1441
62.8k
  *p++ = 'T';
1442
62.8k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
62.8k
  else
1447
62.8k
    *p++ = '+';
1448
62.8k
  p = fxDatePrint2Digits(p, offset / 60);
1449
62.8k
  p = fxDatePrint2Digits(p, offset % 60);
1450
62.8k
  return p;
1451
62.8k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
66.3k
{
1455
66.3k
  if ((value < 0) || (9999 < value)) {
1456
4.24k
    if (value < 0) {
1457
2.02k
      *p++ = '-';
1458
2.02k
      value = -value;
1459
2.02k
    }
1460
2.21k
    else
1461
2.21k
      *p++ = '+';
1462
4.24k
    if (99999 < value) {
1463
1.42k
      *p++ = '0' + value / 100000;
1464
1.42k
      value %= 100000;
1465
1.42k
    }
1466
4.24k
    if (9999 < value) {
1467
2.86k
      *p++ = '0' + value / 10000;
1468
2.86k
      value %= 10000;
1469
2.86k
    }
1470
4.24k
  }
1471
66.3k
  return fxDatePrint4Digits(p, value);
1472
66.3k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
113k
{
1476
113k
  txInteger leap, day;
1477
113k
  if ((1970 <= year) && (year < 2038))
1478
34.6k
    return year;
1479
79.1k
  leap = mxIsLeapYear(year);
1480
79.1k
  year += mxYearsOffset - 1;
1481
79.1k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
79.1k
  day = (day + 4) % 7;
1483
79.1k
  if (day < 0)
1484
61.9k
    day += 7; 
1485
79.1k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
113k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
115k
{
1490
115k
  txInteger date, time, year, leap, month;
1491
115k
  const txInteger* monthsDays;
1492
115k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
115k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
115k
  if (time < 0) {
1495
1.65k
    date--;
1496
1.65k
    time += (txInteger)mxDayMilliseconds;
1497
1.65k
  }
1498
115k
  dt->offset = 0;
1499
115k
  dt->day = (date + 4) % 7;
1500
115k
  if (dt->day < 0)
1501
57.3k
    dt->day += 7; 
1502
115k
  dt->milliseconds = time % 1000;
1503
115k
  time /= 1000;
1504
115k
  dt->seconds = time % 60;
1505
115k
  time /= 60;
1506
115k
  dt->minutes = time % 60;
1507
115k
  time /= 60;
1508
115k
  dt->hours = time;
1509
115k
    date += mxYearDays(1970 + mxYearsOffset);
1510
115k
    year = 400 * (date / mx400YearsDays);
1511
115k
  date %= mx400YearsDays;
1512
115k
  date--;
1513
115k
  year += 100 * (date / mx100YearsDays);
1514
115k
  date %= mx100YearsDays;
1515
115k
  date++;
1516
115k
  year += 4 * (date / mx4YearsDays);
1517
115k
  date %= mx4YearsDays;
1518
115k
  date--;
1519
115k
  year += date / mx1YearDays;
1520
115k
    date %= mx1YearDays;
1521
115k
  year -= mxYearsOffset;
1522
115k
  leap = mxIsLeapYear(year);
1523
115k
    date += leap;
1524
115k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
805k
    for (month = 0; month < 11; month++) {
1526
798k
      if (date < monthsDays[month + 1])
1527
108k
        break;
1528
798k
    }
1529
115k
    date -= monthsDays[month];
1530
115k
  dt->date = date + 1;
1531
115k
  dt->month = month;
1532
115k
  dt->year = year;
1533
115k
  if (!utc) {
1534
66.9k
    txNumber former = value;
1535
66.9k
    txInteger similar;
1536
66.9k
    c_time_t time;
1537
66.9k
    c_tm tm;
1538
66.9k
    similar = fxDateSimilarYear(year);
1539
66.9k
    if (similar != year) {
1540
37.1k
      dt->year = similar;
1541
37.1k
      value = fxDateMerge(dt, 1);
1542
37.1k
    }
1543
66.9k
    time = (txInteger)c_floor(value / 1000.0);
1544
66.9k
    tm = *c_localtime(&time);
1545
66.9k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
66.9k
    dt->day = tm.tm_wday;
1547
66.9k
    dt->seconds = tm.tm_sec;
1548
66.9k
    dt->minutes = tm.tm_min;
1549
66.9k
    dt->hours = tm.tm_hour;
1550
66.9k
    dt->date = tm.tm_mday;
1551
66.9k
    dt->month = tm.tm_mon;
1552
66.9k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
66.9k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
66.9k
  }
1555
115k
  dt->value = value;
1556
115k
}
1557
1558
1559
1560