Coverage Report

Created: 2026-01-29 06:33

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
27.5k
{
79
27.5k
  txSlot* slot;
80
27.5k
  mxPush(mxObjectPrototype);
81
27.5k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
82
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMilliseconds), 0, mxID(_getMilliseconds), XS_DONT_ENUM_FLAG);
83
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getSeconds), 0, mxID(_getSeconds), XS_DONT_ENUM_FLAG);
84
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMinutes), 0, mxID(_getMinutes), XS_DONT_ENUM_FLAG);
85
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getHours), 0, mxID(_getHours), XS_DONT_ENUM_FLAG);
86
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDay), 0, mxID(_getDay), XS_DONT_ENUM_FLAG);
87
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getDate), 0, mxID(_getDate), XS_DONT_ENUM_FLAG);
88
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getMonth), 0, mxID(_getMonth), XS_DONT_ENUM_FLAG);
89
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getYear), 0, mxID(_getYear), XS_DONT_ENUM_FLAG);
90
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getFullYear), 0, mxID(_getFullYear), XS_DONT_ENUM_FLAG);
91
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMilliseconds), 0, mxID(_getUTCMilliseconds), XS_DONT_ENUM_FLAG);
92
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCSeconds), 0, mxID(_getUTCSeconds), XS_DONT_ENUM_FLAG);
93
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMinutes), 0, mxID(_getUTCMinutes), XS_DONT_ENUM_FLAG);
94
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCHours), 0, mxID(_getUTCHours), XS_DONT_ENUM_FLAG);
95
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDay), 0, mxID(_getUTCDay), XS_DONT_ENUM_FLAG);
96
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCDate), 0, mxID(_getUTCDate), XS_DONT_ENUM_FLAG);
97
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCMonth), 0, mxID(_getUTCMonth), XS_DONT_ENUM_FLAG);
98
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getUTCFullYear), 0, mxID(_getUTCFullYear), XS_DONT_ENUM_FLAG);
99
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_getTime), XS_DONT_ENUM_FLAG);
100
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_getTimezoneOffset), 0, mxID(_getTimezoneOffset), XS_DONT_ENUM_FLAG);
101
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setDate), 1, mxID(_setDate), XS_DONT_ENUM_FLAG);
102
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setFullYear), 3, mxID(_setFullYear), XS_DONT_ENUM_FLAG);
103
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setHours), 4, mxID(_setHours), XS_DONT_ENUM_FLAG);
104
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMilliseconds), 1, mxID(_setMilliseconds), XS_DONT_ENUM_FLAG);
105
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMinutes), 3, mxID(_setMinutes), XS_DONT_ENUM_FLAG);
106
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setMonth), 2, mxID(_setMonth), XS_DONT_ENUM_FLAG);
107
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setSeconds), 2, mxID(_setSeconds), XS_DONT_ENUM_FLAG);
108
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setTime), 1, mxID(_setTime), XS_DONT_ENUM_FLAG);
109
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setYear), 1, mxID(_setYear), XS_DONT_ENUM_FLAG);
110
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCDate), 1, mxID(_setUTCDate), XS_DONT_ENUM_FLAG);
111
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCFullYear), 3, mxID(_setUTCFullYear), XS_DONT_ENUM_FLAG);
112
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCHours), 4, mxID(_setUTCHours), XS_DONT_ENUM_FLAG);
113
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMilliseconds), 1, mxID(_setUTCMilliseconds), XS_DONT_ENUM_FLAG);
114
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMinutes), 3, mxID(_setUTCMinutes), XS_DONT_ENUM_FLAG);
115
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCMonth), 2, mxID(_setUTCMonth), XS_DONT_ENUM_FLAG);
116
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_setUTCSeconds), 2, mxID(_setUTCSeconds), XS_DONT_ENUM_FLAG);
117
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toDateString), XS_DONT_ENUM_FLAG);
118
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toISOString), 0, mxID(_toISOString), XS_DONT_ENUM_FLAG);
119
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toJSON), 1, mxID(_toJSON), XS_DONT_ENUM_FLAG);
120
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toDateString), 0, mxID(_toLocaleDateString), XS_DONT_ENUM_FLAG);
121
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
122
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toLocaleTimeString), XS_DONT_ENUM_FLAG);
123
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
124
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toTimeString), 0, mxID(_toTimeString), XS_DONT_ENUM_FLAG);
125
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toUTCString), 0, mxID(_toUTCString), XS_DONT_ENUM_FLAG);
126
27.5k
  slot = fxNextSlotProperty(the, slot, slot, mxID(_toGMTString), XS_DONT_ENUM_FLAG);
127
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
128
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_prototype_toPrimitive), 1, mxID(_Symbol_toPrimitive), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
129
27.5k
  mxDatePrototype = *the->stack;
130
27.5k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Date), 7, mxID(_Date));
131
27.5k
  mxDateConstructor = *the->stack;
132
27.5k
  slot = fxLastProperty(the, slot);
133
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_now), 0, mxID(_now), XS_DONT_ENUM_FLAG);
134
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_parse), 1, mxID(_parse), XS_DONT_ENUM_FLAG);
135
27.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Date_UTC), 7, mxID(_UTC), XS_DONT_ENUM_FLAG);
136
27.5k
  mxPop();
137
27.5k
}
138
139
txSlot* fxNewDateInstance(txMachine* the)
140
102k
{
141
102k
  txSlot* instance;
142
102k
  txSlot* property;
143
102k
  instance = fxNewObjectInstance(the);
144
102k
  property = fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
145
102k
  property->kind = XS_DATE_KIND;
146
102k
  property->value.number = C_NAN;
147
102k
  return instance;
148
102k
}
149
150
void fx_Date(txMachine* the)
151
111k
{
152
111k
  fx_Date_aux(the, 0);
153
111k
}
154
155
void fx_Date_aux(txMachine* the, txFlag secure)
156
111k
{
157
111k
  txInteger c = mxArgc;
158
111k
  txDateTime dt;
159
111k
  txSlot* instance;
160
111k
  if (mxIsUndefined(mxTarget)) {
161
8.21k
    char buffer[256];
162
8.21k
    txString p = buffer;
163
8.21k
    txDateTime dt;
164
8.21k
    if (secure)
165
0
      mxTypeError("secure mode");
166
8.21k
    mxResult->value.number = fxDateNow();
167
8.21k
    mxResult->kind = XS_NUMBER_KIND;
168
8.21k
    fxDateSplit(mxResult->value.number, 0, &dt);
169
8.21k
    p = fxDatePrintDay(p, dt.day);
170
8.21k
    *p++ = ' ';
171
8.21k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
172
8.21k
    *p++ = ' ';
173
8.21k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
174
8.21k
    *p++ = ' ';
175
8.21k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
176
8.21k
    *p = 0;
177
8.21k
    fxCopyStringC(the, mxResult, buffer);
178
8.21k
    return;
179
8.21k
  }
180
102k
  mxPushSlot(mxTarget);
181
102k
  fxGetPrototypeFromConstructor(the, &mxDatePrototype);
182
102k
  instance = fxNewDateInstance(the);
183
102k
  mxPullSlot(mxResult);
184
102k
  if (c > 1) {
185
14.8k
    dt.year = fxDateFullYear(the, mxArgv(0));
186
14.8k
    dt.month = fxToNumber(the, mxArgv(1));
187
14.8k
    dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
188
14.8k
    dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
189
14.8k
    dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
190
14.8k
    dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
191
14.8k
    dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
192
14.8k
    instance->next->value.number = fxDateMerge(&dt, 0);
193
14.8k
    return;
194
14.8k
  }
195
88.0k
  if (c > 0) {
196
86.1k
    txSlot* slot = mxArgv(0);
197
86.1k
    if (slot->kind == XS_REFERENCE_KIND) {
198
491
      txSlot* date = slot->value.reference;
199
491
      if ((date->next) && (date->next->kind == XS_DATE_KIND)) {
200
16
        instance->next->value.number = date->next->value.number;
201
16
        return;
202
16
      }
203
491
    }
204
86.0k
    fxToPrimitive(the, slot, XS_NO_HINT);
205
86.0k
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
206
8.22k
      mxPushSlot(mxFunction);
207
8.22k
      mxDub();
208
8.22k
      mxGetID(mxID(_parse));
209
8.22k
      mxCall();
210
8.22k
      mxPushSlot(slot);
211
8.22k
      mxRunCount(1);
212
8.22k
      instance->next->value.number = the->stack->value.number;
213
8.22k
      mxPop();
214
8.22k
      return;
215
8.22k
    }
216
77.8k
    instance->next->value.number = fxDateClip(fxToNumber(the, slot));
217
77.8k
    return;
218
86.0k
  }
219
1.96k
  if (secure)
220
0
    mxTypeError("secure mode");
221
1.96k
  instance->next->value.number = fxDateNow();
222
1.96k
}
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
1.02M
{
242
1.02M
  txByte c = *theCharacter;
243
1.02M
  txString p = *theString;
244
1.02M
  txInteger aResult = c - '0';
245
1.02M
  c = c_read8(p++);
246
2.00M
  while (('0' <= c) && (c <= '9')) {
247
981k
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
248
981k
    if (__builtin_mul_overflow(aResult, 10, &aResult) ||
249
971k
      __builtin_add_overflow(aResult, c - '0', &aResult))
250
19.0k
      *overflow = 1;
251
#else
252
    aResult = (aResult * 10) + c - '0';
253
    if (aResult < 0)
254
      *overflow = 1;
255
#endif
256
981k
    c = c_read8(p++);
257
981k
  }
258
1.02M
  *theCharacter = c;
259
1.02M
  *theString = p;
260
1.02M
  return aResult;
261
1.02M
}
262
263
txInteger fx_Date_parse_fraction(txByte* theCharacter, txString* theString)
264
3.11k
{
265
3.11k
  txByte c = *theCharacter;
266
3.11k
  txString p = *theString;
267
3.11k
  txNumber fraction = 100;
268
3.11k
  txNumber aResult = ((c - '0') * fraction);
269
3.11k
  c = c_read8(p++);
270
5.11k
  while (('0' <= c) && (c <= '9')) {
271
2.00k
    fraction /= 10;
272
2.00k
    aResult = aResult + ((c - '0') * fraction);
273
2.00k
    c = c_read8(p++);
274
2.00k
  }
275
3.11k
  *theCharacter = c;
276
3.11k
  *theString = p;
277
3.11k
  return (txInteger)c_trunc(aResult);
278
3.11k
}
279
280
void fx_Date_parse(txMachine* the)
281
514k
{
282
1.40M
  #define mxDayCount 7
283
514k
  static const char* const gxDays[mxDayCount] ICACHE_RODATA_ATTR = {
284
514k
    "monday", 
285
514k
    "tuesday", 
286
514k
    "wednesday", 
287
514k
    "thursday", 
288
514k
    "friday",
289
514k
    "saturday", 
290
514k
    "sunday"
291
514k
  };
292
2.14M
  #define mxMonthCount 12
293
514k
  static const char* const gxMonths[mxMonthCount] ICACHE_RODATA_ATTR = {
294
514k
    "january",
295
514k
    "february",
296
514k
    "march",
297
514k
    "april",
298
514k
    "may",
299
514k
    "june",
300
514k
    "july",
301
514k
    "august",
302
514k
    "september",
303
514k
    "october",
304
514k
    "november",
305
514k
    "december"
306
514k
  };
307
1.95M
  #define mxZoneCount 11
308
514k
  static const char* const gxZones[mxZoneCount] ICACHE_RODATA_ATTR = {
309
514k
    "gmt", "ut", "utc",
310
514k
    "est", "edt",
311
514k
    "cst", "cdt",
312
514k
    "mst", "mdt",
313
514k
    "pst", "pdt"
314
514k
  };
315
514k
  static const int gxDeltas[mxZoneCount] ICACHE_XS6RO2_ATTR = {
316
514k
    0, 0, 0,
317
514k
    -5, -4,
318
514k
    -6, -5,
319
514k
    -7, -6,
320
514k
    -8, -7
321
514k
  };
322
  
323
514k
  txString aString;
324
514k
  txBoolean overflow = 0;
325
514k
  txDateTime dt;
326
514k
  txString p;
327
514k
  txString q;
328
514k
  txByte c;
329
514k
  char buffer[10];  /* base type should be the same as txString */
330
514k
  txInteger aComment;
331
514k
  txInteger aDelta;
332
514k
  txInteger aValue;
333
514k
  txSize aLength;
334
514k
  txInteger i;
335
514k
  txInteger yearSign = 1;
336
    
337
514k
  if (mxArgc < 1)
338
0
    goto fail;
339
514k
  aString = fxToString(the, mxArgv(0));
340
  
341
514k
  dt.seconds = -1;
342
514k
  dt.minutes = -1;
343
514k
  dt.hours = -1;
344
514k
  dt.date = -1;
345
514k
  dt.month = -1;
346
514k
  dt.year = -1;
347
514k
  dt.milliseconds = -1;
348
514k
  aComment = 0;
349
514k
  aDelta = -1;
350
351
514k
  c = c_read8(aString++);
352
11.3M
  while (c) {
353
11.2M
    if (c == '(') {
354
1.90k
      aComment++;
355
1.90k
      c = c_read8(aString++);
356
1.90k
      continue;
357
1.90k
    }
358
11.2M
    else if (c == ')') {
359
6.32k
      if (aComment) {
360
559
        aComment--;
361
559
        c = c_read8(aString++);
362
559
        continue;
363
559
      }
364
5.77k
      else
365
5.77k
        goto fail;
366
6.32k
    }
367
11.2M
    else if (aComment) {
368
74.1k
      c = c_read8(aString++);
369
74.1k
      continue;
370
74.1k
    }  
371
    
372
11.1M
    if ((c <= ' ') || (c == ',')) {
373
10.1M
      c = c_read8(aString++);
374
10.1M
      continue;
375
10.1M
    }
376
      
377
1.08M
    else if ((c == '-') | (c == '+')) {
378
29.9k
            txInteger aSign;
379
29.9k
      if (c == '-')  
380
28.5k
        aSign = -1;
381
1.39k
      else
382
1.39k
        aSign = 1;
383
29.9k
      c = c_read8(aString++);
384
29.9k
      if (('0' <= c) && (c <= '9')) {
385
28.6k
        aValue = fx_Date_parse_number(&c, &aString, &overflow);
386
28.6k
        if (c == '-') {
387
6.55k
          if (dt.year >= 0)
388
1.00k
            goto fail;
389
5.54k
          dt.year = aValue;
390
5.54k
          yearSign = aSign;
391
5.54k
          c = c_read8(aString++);
392
5.54k
          if (('0' <= c) && (c <= '9')) {
393
5.01k
            dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
394
5.01k
            if (c == '-') {
395
3.22k
              c = c_read8(aString++);
396
3.22k
              if (('0' <= c) && (c <= '9'))
397
2.96k
                dt.date = fx_Date_parse_number(&c, &aString, &overflow);
398
258
              else
399
258
                dt.date = 1;
400
3.22k
            }
401
5.01k
          }
402
533
          else
403
533
            dt.month = 0;
404
5.54k
        }
405
22.1k
        else {
406
22.1k
          if ((aDelta != 0) && (aDelta != -1))
407
1.82k
            goto fail;
408
20.3k
          if (c == ':') {
409
3.52k
            aDelta = 60 * aValue;
410
3.52k
            c = c_read8(aString++);
411
3.52k
            if (('0' <= c) && (c <= '9')) {
412
1.78k
              aDelta += fx_Date_parse_number(&c, &aString, &overflow);
413
1.78k
            }
414
3.52k
          }
415
16.7k
          else {
416
16.7k
            if (aValue < 24)
417
12.2k
              aDelta = aValue * 60;
418
4.53k
            else
419
4.53k
              aDelta = (aValue % 100) + ((aValue / 100) * 60);
420
16.7k
          }
421
20.3k
          aDelta *= aSign;
422
20.3k
        }
423
28.6k
      }
424
1.25k
      else
425
1.25k
        goto fail;
426
29.9k
    }    
427
1.05M
    else if (('0' <= c) && (c <= '9')) {
428
477k
      aValue = fx_Date_parse_number(&c, &aString, &overflow);
429
477k
      if (c == ':') {
430
126k
        if (dt.hours >= 0) 
431
1.13k
          goto fail;
432
125k
        dt.hours = aValue;  
433
125k
        c = c_read8(aString++);
434
125k
        if (('0' <= c) && (c <= '9')) {
435
112k
          dt.minutes = fx_Date_parse_number(&c, &aString, &overflow);
436
112k
          if (c == ':') {
437
108k
            c = c_read8(aString++);
438
108k
            if (('0' <= c) && (c <= '9')) {
439
105k
              dt.seconds = fx_Date_parse_number(&c, &aString, &overflow);
440
105k
              if (c == '.') {
441
6.91k
                c = c_read8(aString++);
442
6.91k
                if (('0' <= c) && (c <= '9')) {
443
3.11k
                  dt.milliseconds = fx_Date_parse_fraction(&c, &aString);
444
3.11k
                }
445
6.91k
              }
446
105k
            }
447
2.54k
            else
448
2.54k
              dt.seconds = 0;
449
108k
          }
450
112k
        }
451
12.9k
        else
452
12.9k
          dt.seconds = 0;
453
125k
      }
454
350k
      else if (c == '/') {
455
8.83k
        if (dt.year >= 0)
456
210
          goto fail;
457
8.62k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
458
8.62k
        c = c_read8(aString++);
459
8.62k
        if (('0' <= c) && (c <= '9')) {
460
8.29k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
461
8.29k
          if (c == '/') {
462
384
            c = c_read8(aString++);
463
384
            if (('0' <= c) && (c <= '9')) {
464
114
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
465
114
            }
466
270
            else
467
270
              dt.date = 1;
468
384
          }
469
8.29k
        }
470
328
        else
471
328
          dt.month = 0;
472
8.62k
      }
473
342k
      else if (c == '-') {
474
282k
        if (dt.year >= 0)
475
1.04k
          goto fail;
476
281k
        dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
477
281k
        c = c_read8(aString++);
478
281k
        if (('0' <= c) && (c <= '9')) {
479
280k
          dt.month = fx_Date_parse_number(&c, &aString, &overflow) - 1;
480
280k
          if (c == '-') {
481
2.50k
            c = c_read8(aString++);
482
2.50k
            if (('0' <= c) && (c <= '9'))
483
2.34k
              dt.date = fx_Date_parse_number(&c, &aString, &overflow);
484
157
            else
485
157
              dt.date = 1;
486
2.50k
          }
487
280k
        }
488
490
        else
489
490
          dt.month = 0;
490
281k
      }
491
59.8k
      else {
492
59.8k
        if (aValue < 70) {
493
51.8k
          if (dt.date < 0)
494
48.5k
            dt.date = aValue;
495
3.25k
          else
496
3.25k
            goto fail;
497
51.8k
        }
498
7.99k
        else {
499
7.99k
          if (dt.year < 0)
500
7.66k
            dt.year = /*(aValue < 100) ? aValue + 1900 :*/ aValue;
501
323
          else
502
323
            goto fail;
503
7.99k
        }
504
59.8k
      }
505
477k
    }        
506
575k
    else if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'))) {
507
357k
      txSize cmpLength;
508
357k
      p = buffer;
509
357k
      q = p + sizeof(buffer) - 1;
510
2.24M
      do {
511
2.24M
        if (p == q) goto fail;
512
2.05M
        *p++ = (c >= 'a') ? c : (c + ('a' - 'A'));
513
2.05M
        c = c_read8(aString++);
514
2.05M
      } while ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
515
169k
      *p = 0;
516
169k
      aLength = mxPtrDiff(p - (txString)buffer);
517
169k
      cmpLength = (aLength >= 3) ? aLength : 3;
518
169k
      if (c_strcmp("am", buffer) == 0) {
519
6.14k
        if ((dt.hours < 0) || (12 <  dt.hours))
520
2.25k
          goto fail;
521
3.88k
        if (dt.hours == 12)
522
2.02k
          dt.hours = 0;
523
3.88k
        continue;
524
6.14k
      }
525
162k
      if (c_strcmp("pm", buffer) == 0) {
526
5.31k
        if ((dt.hours < 0) || (12 <  dt.hours))
527
2.60k
          goto fail;
528
2.71k
        if (dt.hours != 12)
529
896
          dt.hours += 12;
530
2.71k
        continue;
531
5.31k
      }
532
1.24M
      for (i = 0; i < mxDayCount; i++)
533
1.09M
        if (c_strncmp(gxDays[i], buffer, cmpLength) == 0)
534
3.04k
          break;
535
157k
      if (i < mxDayCount)
536
3.04k
        continue;
537
1.98M
      for (i = 0; i < mxMonthCount; i++)
538
1.83M
        if (c_strncmp(gxMonths[i], buffer, cmpLength) == 0)
539
3.17k
          break;
540
154k
      if (i < mxMonthCount) {
541
3.17k
        if (dt.month < 0) {
542
3.04k
          dt.month = i;
543
3.04k
          continue;
544
3.04k
        }
545
129
        else
546
129
          goto fail;
547
3.17k
      }
548
1.79M
      for (i = 0; i < mxZoneCount; i++)
549
1.64M
        if (c_strcmp(gxZones[i], buffer) == 0)
550
1.79k
          break;
551
151k
      if (i < mxZoneCount) {
552
1.79k
        if (aDelta == -1) {
553
1.34k
          aDelta = gxDeltas[i] * 60;
554
1.34k
          continue;
555
1.34k
        }
556
450
        else
557
450
          goto fail;
558
1.79k
      }
559
149k
      if (c_strcmp("t", buffer) == 0) {
560
98.0k
        if (dt.year < 0) 
561
18
          goto fail;
562
98.0k
        continue;
563
98.0k
      }
564
51.6k
      if (c_strcmp("z", buffer) == 0) {
565
9.54k
        if (dt.hours < 0) 
566
1.36k
          goto fail;
567
8.18k
        aDelta = 0;
568
8.18k
        continue;
569
9.54k
      }
570
42.0k
      goto fail;
571
51.6k
    }
572
217k
    else
573
217k
      goto fail;
574
11.1M
  }
575
43.6k
   if (overflow)
576
148
       goto fail;
577
43.5k
   if (dt.year < 0)
578
4.69k
       goto fail;
579
38.8k
  if ((yearSign < 0) && (dt.year == 0))
580
235
       goto fail;
581
38.6k
  if (dt.month < 0)
582
3.85k
    dt.month = 0;
583
38.6k
  if (dt.date < 0)
584
3.93k
    dt.date = 1;
585
38.6k
  if ((aDelta < 0) && (dt.hours < 0) && (dt.minutes < 0) && (dt.seconds < 0) && (dt.milliseconds < 0))
586
341
    aDelta = 0;
587
38.6k
  if (dt.hours < 0)
588
741
    dt.hours = 0;
589
38.6k
  if (dt.minutes < 0)
590
5.14k
    dt.minutes = 0;
591
38.6k
    if (dt.seconds < 0)
592
1.64k
        dt.seconds = 0;
593
38.6k
    if (dt.milliseconds < 0)
594
38.5k
        dt.milliseconds = 0;
595
38.6k
    dt.year *= yearSign;
596
38.6k
  mxResult->value.number = fxDateMerge(&dt, (aDelta != -1) ? 1 : 0);
597
38.6k
  if (aDelta != -1)
598
2.93k
    mxResult->value.number -= (txNumber)aDelta * 60000.0;
599
38.6k
  mxResult->kind = XS_NUMBER_KIND;
600
38.6k
  return;
601
475k
fail:
602
475k
  mxResult->value.number = C_NAN;
603
475k
  mxResult->kind = XS_NUMBER_KIND;
604
  //mxSyntaxError("invalid parameter");
605
475k
}
606
607
void fx_Date_UTC(txMachine* the)
608
79.3k
{
609
79.3k
  txInteger c = mxArgc;
610
79.3k
  txDateTime dt;
611
79.3k
  dt.year = (c > 0) ? fxDateFullYear(the, mxArgv(0)) : C_NAN;
612
79.3k
  dt.month = (c > 1) ? fxToNumber(the, mxArgv(1)) : 0;
613
79.3k
  dt.date = (c > 2) ? fxToNumber(the, mxArgv(2)) : 1;
614
79.3k
  dt.hours = (c > 3) ? fxToNumber(the, mxArgv(3)) : 0;
615
79.3k
  dt.minutes = (c > 4) ? fxToNumber(the, mxArgv(4)) : 0;
616
79.3k
  dt.seconds = (c > 5) ?fxToNumber(the, mxArgv(5)) : 0;
617
79.3k
  dt.milliseconds = (c > 6) ? fxToNumber(the, mxArgv(6)) : 0;
618
79.3k
  mxResult->value.number = fxDateMerge(&dt, 1);
619
79.3k
    mxResult->kind = XS_NUMBER_KIND;
620
79.3k
}
621
622
txBoolean fx_Date_prototype_get_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
623
100k
{
624
100k
  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
100k
  number = slot->value.number;
636
100k
  if (c_isnan(number)) {
637
82.4k
    mxResult->value.number = C_NAN;
638
82.4k
    mxResult->kind = XS_NUMBER_KIND;
639
82.4k
    dt->value = C_NAN;
640
82.4k
    return 0;
641
82.4k
  }
642
18.2k
  fxDateSplit(slot->value.number, utc, dt);
643
18.2k
  return 1;
644
100k
}
645
646
void fx_Date_prototype_set_aux(txMachine* the, txDateTime* dt, txBoolean utc, txSlot* slot)
647
504
{
648
504
  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
504
  if (c_isnan(number))
661
216
    return;
662
288
  if (slot->flag & XS_DONT_SET_FLAG)
663
0
    mxTypeError("this: read-only Date instance");
664
288
  mxResult->value.number = slot->value.number = fxDateMerge(dt, utc);
665
288
  mxResult->kind = XS_NUMBER_KIND;
666
288
}
667
668
void fx_Date_prototype_getMilliseconds(txMachine* the)
669
60
{
670
60
  txDateTime dt;
671
60
  txSlot* slot = fxDateCheck(the);
672
60
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
673
16
    mxResult->value.integer = (txInteger)dt.milliseconds;
674
16
    mxResult->kind = XS_INTEGER_KIND;
675
16
  }
676
60
}
677
678
void fx_Date_prototype_getSeconds(txMachine* the)
679
33
{
680
33
  txDateTime dt;
681
33
  txSlot* slot = fxDateCheck(the);
682
33
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
683
13
    mxResult->value.integer = (txInteger)dt.seconds;
684
13
    mxResult->kind = XS_INTEGER_KIND;
685
13
  }
686
33
}
687
688
void fx_Date_prototype_getMinutes(txMachine* the)
689
36
{
690
36
  txDateTime dt;
691
36
  txSlot* slot = fxDateCheck(the);
692
36
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
693
14
    mxResult->value.integer = (txInteger)dt.minutes;
694
14
    mxResult->kind = XS_INTEGER_KIND;
695
14
  }
696
36
}
697
698
void fx_Date_prototype_getHours(txMachine* the)
699
37
{
700
37
  txDateTime dt;
701
37
  txSlot* slot = fxDateCheck(the);
702
37
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
703
15
    mxResult->value.integer = (txInteger)dt.hours;
704
15
    mxResult->kind = XS_INTEGER_KIND;
705
15
  }
706
37
}
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
9
    mxResult->value.integer = dt.day;
714
9
    mxResult->kind = XS_INTEGER_KIND;
715
9
  }
716
76.0k
}
717
718
void fx_Date_prototype_getDate(txMachine* the)
719
35
{
720
35
  txDateTime dt;
721
35
  txSlot* slot = fxDateCheck(the);
722
35
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
723
9
    mxResult->value.integer = (txInteger)dt.date;
724
9
    mxResult->kind = XS_INTEGER_KIND;
725
9
  }
726
35
}
727
728
void fx_Date_prototype_getMonth(txMachine* the)
729
31
{
730
31
  txDateTime dt;
731
31
  txSlot* slot = fxDateCheck(the);
732
31
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
733
16
    mxResult->value.integer = (txInteger)dt.month;
734
16
    mxResult->kind = XS_INTEGER_KIND;
735
16
  }
736
31
}
737
738
void fx_Date_prototype_getYear(txMachine* the)
739
1
{
740
1
  txDateTime dt;
741
1
  txSlot* slot = fxDateCheck(the);
742
1
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
743
0
    mxResult->value.integer = (txInteger)dt.year - 1900;
744
0
    mxResult->kind = XS_INTEGER_KIND;
745
0
  }
746
1
}
747
748
void fx_Date_prototype_getFullYear(txMachine* the)
749
29
{
750
29
  txDateTime dt;
751
29
  txSlot* slot = fxDateCheck(the);
752
29
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
753
11
    mxResult->value.integer = (txInteger)dt.year;
754
11
    mxResult->kind = XS_INTEGER_KIND;
755
11
  }
756
29
}
757
758
void fx_Date_prototype_getUTCMilliseconds(txMachine* the)
759
64
{
760
64
  txDateTime dt;
761
64
  txSlot* slot = fxDateCheck(the);
762
64
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
763
12
    mxResult->value.integer = (txInteger)dt.milliseconds;
764
12
    mxResult->kind = XS_INTEGER_KIND;
765
12
  }
766
64
}
767
768
void fx_Date_prototype_getUTCSeconds(txMachine* the)
769
597
{
770
597
  txDateTime dt;
771
597
  txSlot* slot = fxDateCheck(the);
772
597
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
773
15
    mxResult->value.integer = (txInteger)dt.seconds;
774
15
    mxResult->kind = XS_INTEGER_KIND;
775
15
  }
776
597
}
777
778
void fx_Date_prototype_getUTCMinutes(txMachine* the)
779
38
{
780
38
  txDateTime dt;
781
38
  txSlot* slot = fxDateCheck(the);
782
38
  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
38
}
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
52
{
800
52
  txDateTime dt;
801
52
  txSlot* slot = fxDateCheck(the);
802
52
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
803
27
    mxResult->value.integer = dt.day;
804
27
    mxResult->kind = XS_INTEGER_KIND;
805
27
  }
806
52
}
807
808
void fx_Date_prototype_getUTCDate(txMachine* the)
809
38
{
810
38
  txDateTime dt;
811
38
  txSlot* slot = fxDateCheck(the);
812
38
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
813
16
    mxResult->value.integer = (txInteger)dt.date;
814
16
    mxResult->kind = XS_INTEGER_KIND;
815
16
  }
816
38
}
817
818
void fx_Date_prototype_getUTCMonth(txMachine* the)
819
38
{
820
38
  txDateTime dt;
821
38
  txSlot* slot = fxDateCheck(the);
822
38
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
823
14
    mxResult->value.integer = (txInteger)dt.month;
824
14
    mxResult->kind = XS_INTEGER_KIND;
825
14
  }
826
38
}
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
10
    mxResult->value.integer = (txInteger)dt.year;
834
10
    mxResult->kind = XS_INTEGER_KIND;
835
10
  }
836
47
}
837
838
void fx_Date_prototype_getTimezoneOffset(txMachine* the)
839
56
{
840
56
  txDateTime dt;
841
56
  txSlot* slot = fxDateCheck(the);
842
56
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
843
14
    mxResult->value.integer = 0 - dt.offset;
844
14
    mxResult->kind = XS_INTEGER_KIND;
845
14
  }
846
56
}
847
848
void fx_Date_prototype_setMilliseconds(txMachine* the)
849
192
{
850
192
  txInteger c = mxArgc;
851
192
  txDateTime dt;
852
192
  txSlot* slot = fxDateCheck(the);
853
192
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
854
192
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
855
192
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
856
192
}
857
858
void fx_Date_prototype_setSeconds(txMachine* the)
859
61
{
860
61
  txInteger c = mxArgc;
861
61
  txDateTime dt;
862
61
  txSlot* slot = fxDateCheck(the);
863
61
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
864
61
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
865
61
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
866
61
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
867
61
}
868
869
void fx_Date_prototype_setMinutes(txMachine* the)
870
1.90k
{
871
1.90k
  txInteger c = mxArgc;
872
1.90k
  txDateTime dt;
873
1.90k
  txSlot* slot = fxDateCheck(the);
874
1.90k
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
875
1.90k
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
876
1.90k
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
877
1.90k
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
878
1.90k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
879
1.90k
}
880
881
void fx_Date_prototype_setHours(txMachine* the)
882
68
{
883
68
  txInteger c = mxArgc;
884
68
  txDateTime dt;
885
68
  txSlot* slot = fxDateCheck(the);
886
68
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
887
68
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
888
68
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
889
68
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
890
68
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
891
68
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
892
68
}
893
894
void fx_Date_prototype_setDate(txMachine* the)
895
51
{
896
51
  txInteger c = mxArgc;
897
51
  txDateTime dt;
898
51
  txSlot* slot = fxDateCheck(the);
899
51
  fx_Date_prototype_get_aux(the, &dt, 0, slot);
900
51
  dt.date = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
901
51
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
902
51
}
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.89k
{
934
1.89k
  txInteger c = mxArgc;
935
1.89k
  txDateTime dt;
936
1.89k
  txSlot* slot = fxDateCheck(the);
937
1.89k
  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.89k
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
944
1.89k
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
945
1.89k
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
946
1.89k
  fx_Date_prototype_set_aux(the, &dt, 0, slot);
947
1.89k
}
948
949
void fx_Date_prototype_setTime(txMachine* the)
950
1.96k
{
951
1.96k
  txSlot* slot = fxDateCheck(the);
952
1.96k
  if (slot->flag & XS_DONT_SET_FLAG)
953
0
    mxTypeError("this: read-only Date instance");
954
1.96k
  if (mxArgc < 1)
955
2
    slot->value.number = C_NAN;
956
1.96k
  else {
957
1.96k
    txNumber number = fxToNumber(the, mxArgv(0));
958
1.96k
    int fpclass = c_fpclassify(number);
959
1.96k
    if (fpclass != C_FP_NAN) {
960
1.92k
      if (c_fabs(number) > 8.64e15)
961
1
        number = C_NAN;
962
1.92k
      else
963
1.92k
        number = c_trunc(number);
964
1.92k
    }
965
1.96k
    slot->value.number = number;
966
1.96k
  }
967
1.96k
  mxResult->value.number = slot->value.number;
968
1.96k
  mxResult->kind = XS_NUMBER_KIND;
969
1.96k
}
970
971
void fx_Date_prototype_setUTCMilliseconds(txMachine* the)
972
8
{
973
8
  txInteger c = mxArgc;
974
8
  txDateTime dt;
975
8
  txSlot* slot = fxDateCheck(the);
976
8
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
977
8
  dt.milliseconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
978
8
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
979
8
}
980
981
void fx_Date_prototype_setUTCSeconds(txMachine* the)
982
10
{
983
10
  txInteger c = mxArgc;
984
10
  txDateTime dt;
985
10
  txSlot* slot = fxDateCheck(the);
986
10
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
987
10
  dt.seconds = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
988
10
  if (c > 1) dt.milliseconds = fxToNumber(the, mxArgv(1));
989
10
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
990
10
}
991
992
void fx_Date_prototype_setUTCMinutes(txMachine* the)
993
21
{
994
21
  txInteger c = mxArgc;
995
21
  txDateTime dt;
996
21
  txSlot* slot = fxDateCheck(the);
997
21
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
998
21
  dt.minutes = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
999
21
  if (c > 1) dt.seconds = fxToNumber(the, mxArgv(1));
1000
21
  if (c > 2) dt.milliseconds = fxToNumber(the, mxArgv(2));
1001
21
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1002
21
}
1003
1004
void fx_Date_prototype_setUTCHours(txMachine* the)
1005
20
{
1006
20
  txInteger c = mxArgc;
1007
20
  txDateTime dt;
1008
20
  txSlot* slot = fxDateCheck(the);
1009
20
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1010
20
  dt.hours = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1011
20
  if (c > 1) dt.minutes = fxToNumber(the, mxArgv(1));
1012
20
  if (c > 2) dt.seconds = fxToNumber(the, mxArgv(2));
1013
20
  if (c > 3) dt.milliseconds = fxToNumber(the, mxArgv(3));
1014
20
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1015
20
}
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
6
{
1040
6
  txInteger c = mxArgc;
1041
6
  txDateTime dt;
1042
6
  txSlot* slot = fxDateCheck(the);
1043
6
  if (c_isnan(slot->value.number)) slot->value.number = 0;
1044
6
  fx_Date_prototype_get_aux(the, &dt, 1, slot);
1045
6
  dt.year = (c > 0) ? fxToNumber(the, mxArgv(0)) : C_NAN;
1046
6
  if (c > 1) dt.month = fxToNumber(the, mxArgv(1));
1047
6
  if (c > 2) dt.date = fxToNumber(the, mxArgv(2));
1048
6
  fx_Date_prototype_set_aux(the, &dt, 1, slot);
1049
6
}
1050
1051
void fx_Date_prototype_toDateString(txMachine* the)
1052
2.28k
{
1053
2.28k
  char buffer[256];
1054
2.28k
  txDateTime dt;
1055
2.28k
  txSlot* slot = fxDateCheck(the);
1056
2.28k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1057
1.55k
    txString p = buffer;
1058
1.55k
    p = fxDatePrintDay(p, dt.day);
1059
1.55k
    *p++ = ' ';
1060
1.55k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1061
1.55k
    *p = 0;
1062
1.55k
  }
1063
730
  else
1064
730
    c_strcpy(buffer, "Invalid Date");
1065
2.28k
  fxCopyStringC(the, mxResult, buffer);
1066
2.28k
}
1067
1068
void fx_Date_prototype_toISOString(txMachine* the)
1069
19
{
1070
19
  char buffer[256];
1071
19
  txDateTime dt;
1072
19
  txSlot* slot = fxDateCheck(the);
1073
19
  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
4
  else
1088
4
        mxRangeError("Invalid Date");
1089
15
  fxCopyStringC(the, mxResult, buffer);
1090
15
}
1091
1092
void fx_Date_prototype_toJSON(txMachine* the)
1093
15
{
1094
15
  fxToInstance(the, mxThis);
1095
15
  mxPushSlot(mxThis);
1096
15
  fxToPrimitive(the, the->stack, XS_NUMBER_HINT);
1097
15
  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
12
  else {   
1102
12
    mxPop();
1103
12
    mxPushSlot(mxThis);
1104
12
    mxDub();
1105
12
    mxGetID(mxID(_toISOString));
1106
12
    mxCall();
1107
12
    mxRunCount(0);
1108
12
    mxPullSlot(mxResult);
1109
12
  }
1110
15
}
1111
1112
void fx_Date_prototype_toPrimitive(txMachine* the)
1113
19.8k
{
1114
19.8k
  if (mxIsReference(mxThis)) {
1115
19.8k
    txInteger hint = XS_NO_HINT;
1116
19.8k
    txInteger ids[2], i;
1117
19.8k
    if (mxArgc > 0) {
1118
19.8k
      txSlot* slot = mxArgv(0);
1119
19.8k
      if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1120
19.8k
        if (!c_strcmp(slot->value.string, "default"))
1121
13.1k
          hint = XS_STRING_HINT;
1122
6.70k
        else if (!c_strcmp(slot->value.string, "number"))
1123
6.67k
          hint = XS_NUMBER_HINT;
1124
29
        else if (!c_strcmp(slot->value.string, "string"))
1125
19
          hint = XS_STRING_HINT;
1126
19.8k
      }
1127
19.8k
    }
1128
19.8k
    if (hint == XS_STRING_HINT) {
1129
13.1k
      ids[0] = mxID(_toString);
1130
13.1k
      ids[1] = mxID(_valueOf);
1131
13.1k
    }
1132
6.70k
    else if (hint == XS_NUMBER_HINT) {
1133
6.67k
      ids[0] = mxID(_valueOf);
1134
6.67k
      ids[1] = mxID(_toString);
1135
6.67k
    }
1136
24
    else
1137
24
        mxTypeError("invalid hint");
1138
19.8k
    for (i = 0; i < 2; i++) {
1139
19.8k
      mxPushSlot(mxThis);
1140
19.8k
      mxPushSlot(mxThis);
1141
19.8k
      mxGetID(ids[i]);
1142
19.8k
      if (fxIsCallable(the, the->stack)) {
1143
19.8k
        mxCall();
1144
19.8k
        mxRunCount(0);
1145
19.8k
        if (mxIsReference(the->stack))
1146
1
          mxPop();
1147
19.8k
        else {
1148
19.8k
          mxPullSlot(mxResult);
1149
19.8k
          return;
1150
19.8k
            }
1151
19.8k
      }
1152
5
      else {
1153
5
        mxPop();
1154
5
        mxPop();
1155
5
      }
1156
19.8k
    }
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
11
  else {
1163
11
        mxTypeError("invalid this");
1164
11
  }
1165
19.8k
}
1166
1167
void fx_Date_prototype_toString(txMachine* the)
1168
13.1k
{
1169
13.1k
  char buffer[256];
1170
13.1k
  txDateTime dt;
1171
13.1k
  txSlot* slot = fxDateCheck(the);
1172
13.1k
  if (fx_Date_prototype_get_aux(the, &dt, 0, slot)) {
1173
11.1k
    txString p = buffer;
1174
11.1k
    p = fxDatePrintDay(p, dt.day);
1175
11.1k
    *p++ = ' ';
1176
11.1k
    p = fxDatePrintDate(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1177
11.1k
    *p++ = ' ';
1178
11.1k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1179
11.1k
    *p++ = ' ';
1180
11.1k
    p = fxDatePrintTimezone(p, (txInteger)dt.offset);
1181
11.1k
    *p = 0;
1182
11.1k
  }
1183
2.09k
  else
1184
2.09k
    c_strcpy(buffer, "Invalid Date");
1185
13.1k
  fxCopyStringC(the, mxResult, buffer);
1186
13.1k
}
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
2.34k
{
1207
2.34k
  char buffer[256];
1208
2.34k
  txDateTime dt;
1209
2.34k
  txSlot* slot = fxDateCheck(the);
1210
2.34k
  if (fx_Date_prototype_get_aux(the, &dt, 1, slot)) {
1211
1.39k
    txString p = buffer;
1212
1.39k
    p = fxDatePrintDay(p, dt.day);
1213
1.39k
    *p++ = ',';
1214
1.39k
    *p++ = ' ';
1215
1.39k
    p = fxDatePrintDateUTC(p, (txInteger)dt.year, (txInteger)dt.month, (txInteger)dt.date);
1216
1.39k
    *p++ = ' ';
1217
1.39k
    p = fxDatePrintTime(p, (txInteger)dt.hours, (txInteger)dt.minutes, (txInteger)dt.seconds);
1218
1.39k
    *p++ = ' ';
1219
1.39k
    *p++ = 'G';
1220
1.39k
    *p++ = 'M';
1221
1.39k
    *p++ = 'T';
1222
1.39k
    *p = 0;
1223
1.39k
  }
1224
942
  else
1225
942
    c_strcpy(buffer, "Invalid Date");
1226
2.34k
  fxCopyStringC(the, mxResult, buffer);
1227
2.34k
}
1228
1229
void fx_Date_prototype_valueOf(txMachine* the)
1230
7.24k
{
1231
7.24k
  txSlot* slot = fxDateCheck(the);
1232
7.24k
  mxResult->kind = XS_NUMBER_KIND;
1233
7.24k
  mxResult->value = slot->value;
1234
7.24k
}
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
608k
#define mx1YearDays 365
1259
456k
#define mx4YearsDays ((4 * mx1YearDays) + 1)
1260
304k
#define mx100YearsDays ((25 * mx4YearsDays) - 1)
1261
152k
#define mx400YearsDays ((4 * mx100YearsDays) + 1)
1262
382k
#define mxDayMilliseconds 86400000.0
1263
#define mxYearDays(YEAR) \
1264
408k
  ((365 * (YEAR)) + ((YEAR) / 4) - ((YEAR) / 100) + ((YEAR) / 400) + 1)
1265
#define mxIsLeapYear(YEAR) \
1266
134k
  (((YEAR) % 4) ? 0 : ((YEAR) % 100) ? 1 : ((YEAR) % 400) ? 0 : 1)
1267
349k
#define mxYearsOffset 400000
1268
1269
txSlot* fxDateCheck(txMachine* the)
1270
110k
{
1271
110k
  txSlot* it = mxThis;
1272
110k
  if (it->kind == XS_REFERENCE_KIND) {
1273
110k
    txSlot* instance = it->value.reference;
1274
110k
    it = instance->next;
1275
110k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_DATE_KIND))
1276
109k
      return it;
1277
110k
  }
1278
110k
  mxTypeError("this: not a Date instance");
1279
0
  return C_NULL;
1280
110k
}
1281
1282
txNumber fxDateClip(txNumber value)
1283
412k
{
1284
412k
  if (!c_isfinite(value))
1285
76.3k
    value = C_NAN;
1286
336k
  else if (c_fabs(value) > 8.64e15)
1287
5.21k
    value = C_NAN;
1288
330k
  else {
1289
330k
    value = c_trunc(value);
1290
330k
    if (value == 0)
1291
2.66k
      value = 0;
1292
330k
  }
1293
412k
  return value; 
1294
412k
}
1295
1296
txNumber fxDateFullYear(txMachine* the, txSlot* slot)
1297
93.9k
{
1298
93.9k
  txNumber result = fxToNumber(the, slot);
1299
93.9k
  if (c_isfinite(result)) {
1300
93.0k
    txInteger value = fxToInteger(the, slot);
1301
93.0k
    if ((0 <= value) && (value <= 99))
1302
87.1k
      result = 1900 + value;
1303
93.0k
  }
1304
93.9k
  return result;
1305
93.9k
}
1306
1307
txNumber fxDateMerge(txDateTime* dt, txBoolean utc)
1308
218k
{
1309
218k
  txNumber year, month;
1310
218k
  txInteger monthIndex;
1311
218k
  txBoolean leap;
1312
218k
  txNumber value;
1313
218k
  if ((!c_isfinite(dt->year))
1314
216k
  || (!c_isfinite(dt->month))
1315
216k
  || (!c_isfinite(dt->date))
1316
216k
  || (!c_isfinite(dt->hours))
1317
216k
  || (!c_isfinite(dt->minutes))
1318
215k
  || (!c_isfinite(dt->seconds))
1319
215k
  || (!c_isfinite(dt->milliseconds)))
1320
3.11k
    return C_NAN;
1321
214k
  year = c_trunc(dt->year);
1322
214k
  month = c_trunc(dt->month);
1323
214k
  year += c_floor(month / 12);
1324
214k
  monthIndex = (txInteger)c_fmod(month, 12.0);
1325
214k
  if (monthIndex < 0)
1326
651
    monthIndex += 12;
1327
214k
  leap = (c_fmod(year, 4) == 0) && ((c_fmod(year, 100) != 0) || (c_fmod(year, 400) == 0));
1328
214k
  year += mxYearsOffset - 1;
1329
214k
  value = (365 * year) + c_floor(year / 4) - c_floor(year / 100) + c_floor(year / 400) + 1;
1330
214k
  value -= (txNumber)mxYearDays(1970 + mxYearsOffset - 1);
1331
214k
  if (leap)
1332
42.7k
    value += gxLeapYearMonthsDays[monthIndex];
1333
172k
  else
1334
172k
    value += gxCommonYearMonthsDays[monthIndex];
1335
214k
  value += c_trunc(dt->date) - 1;
1336
214k
  value *= mxDayMilliseconds;
1337
214k
  value += c_trunc(dt->hours) * 60 * 60 * 1000;
1338
214k
  value += c_trunc(dt->minutes) * 60 * 1000;
1339
214k
  value += c_trunc(dt->seconds) * 1000;
1340
214k
    value += c_trunc(dt->milliseconds);
1341
214k
  if (!utc) {
1342
49.5k
    txNumber former = value;
1343
49.5k
    txInteger similar;
1344
49.5k
    c_tm tm;
1345
49.5k
    c_time_t time;
1346
49.5k
    fxDateSplit(value, 1, dt);
1347
49.5k
    similar = fxDateSimilarYear((txInteger)dt->year);
1348
49.5k
    c_memset(&tm, 0, sizeof(c_tm));
1349
49.5k
    tm.tm_year = similar - 1900;
1350
49.5k
    tm.tm_mon = (txInteger)dt->month;
1351
49.5k
    tm.tm_mday = (txInteger)dt->date;
1352
49.5k
    tm.tm_hour = (txInteger)dt->hours;
1353
49.5k
    tm.tm_min = (txInteger)dt->minutes;
1354
49.5k
    tm.tm_sec = (txInteger)dt->seconds;
1355
49.5k
    tm.tm_isdst =-1;
1356
49.5k
    time = c_mktime(&tm);  
1357
49.5k
    if (time == -1)
1358
0
      value = NAN;
1359
49.5k
    else {
1360
49.5k
      value = (txNumber)time;
1361
49.5k
      value *= 1000;
1362
49.5k
      value += dt->milliseconds;
1363
49.5k
      if (similar != year) {
1364
49.5k
        dt->year = similar;
1365
49.5k
        value += former - fxDateMerge(dt, 1);
1366
49.5k
      }
1367
49.5k
    }
1368
49.5k
  }
1369
214k
  return fxDateClip(value);
1370
218k
}
1371
1372
txNumber fxDateNow()
1373
119k
{
1374
119k
  c_timeval tv;
1375
119k
  c_gettimeofday(&tv, NULL);
1376
119k
  return fxDateClip(((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec / 1000)));
1377
119k
}
1378
1379
txString fxDatePrint2Digits(txString p, txInteger value)
1380
145k
{
1381
145k
  *p++ = '0' + value / 10;
1382
145k
  *p++ = '0' + value % 10;
1383
145k
  return p;
1384
145k
}
1385
1386
txString fxDatePrint3Digits(txString p, txInteger value)
1387
22.2k
{
1388
22.2k
  *p++ = '0' + value / 100;
1389
22.2k
  return fxDatePrint2Digits(p, value % 100);
1390
22.2k
}
1391
1392
txString fxDatePrint4Digits(txString p, txInteger value)
1393
22.2k
{
1394
22.2k
  *p++ = '0' + value / 1000;
1395
22.2k
  return fxDatePrint3Digits(p, value % 1000);
1396
22.2k
}
1397
1398
txString fxDatePrintDate(txString p, txInteger year, txInteger month, txInteger date)
1399
20.8k
{
1400
20.8k
  c_strcpy(p, gxMonthNames[month]);
1401
20.8k
  p += 3;
1402
20.8k
  *p++ = ' ';
1403
20.8k
  p = fxDatePrint2Digits(p, date);
1404
20.8k
  *p++ = ' ';
1405
20.8k
  p = fxDatePrintYear(p, year);
1406
20.8k
  return p;
1407
20.8k
}
1408
1409
txString fxDatePrintDateUTC(txString p, txInteger year, txInteger month, txInteger date)
1410
1.39k
{
1411
1.39k
  p = fxDatePrint2Digits(p, date);
1412
1.39k
  *p++ = ' ';
1413
1.39k
  c_strcpy(p, gxMonthNames[month]);
1414
1.39k
  p += 3;
1415
1.39k
  *p++ = ' ';
1416
1.39k
  p = fxDatePrintYear(p, year);
1417
1.39k
  return p;
1418
1.39k
}
1419
1420
txString fxDatePrintDay(txString p, txInteger day)
1421
22.2k
{
1422
22.2k
  c_strcpy(p, gxDayNames[day]);
1423
22.2k
  p += 3;
1424
22.2k
  return p;
1425
22.2k
}
1426
1427
txString fxDatePrintTime(txString p, txInteger hours, txInteger minutes, txInteger seconds)
1428
20.7k
{
1429
20.7k
  p = fxDatePrint2Digits(p, hours);
1430
20.7k
  *p++ = ':';
1431
20.7k
  p = fxDatePrint2Digits(p, minutes);
1432
20.7k
  *p++ = ':';
1433
20.7k
  p = fxDatePrint2Digits(p, seconds);
1434
20.7k
  return p;
1435
20.7k
}
1436
1437
txString fxDatePrintTimezone(txString p, txInteger offset)
1438
19.3k
{
1439
19.3k
  *p++ = 'G';
1440
19.3k
  *p++ = 'M';
1441
19.3k
  *p++ = 'T';
1442
19.3k
  if (offset < 0) {
1443
0
    offset = 0 - offset;
1444
0
    *p++ = '-';
1445
0
  }
1446
19.3k
  else
1447
19.3k
    *p++ = '+';
1448
19.3k
  p = fxDatePrint2Digits(p, offset / 60);
1449
19.3k
  p = fxDatePrint2Digits(p, offset % 60);
1450
19.3k
  return p;
1451
19.3k
}
1452
1453
txString fxDatePrintYear(txString p, txInteger value)
1454
22.2k
{
1455
22.2k
  if ((value < 0) || (9999 < value)) {
1456
1.99k
    if (value < 0) {
1457
623
      *p++ = '-';
1458
623
      value = -value;
1459
623
    }
1460
1.36k
    else
1461
1.36k
      *p++ = '+';
1462
1.99k
    if (99999 < value) {
1463
1.23k
      *p++ = '0' + value / 100000;
1464
1.23k
      value %= 100000;
1465
1.23k
    }
1466
1.99k
    if (9999 < value) {
1467
1.54k
      *p++ = '0' + value / 10000;
1468
1.54k
      value %= 10000;
1469
1.54k
    }
1470
1.99k
  }
1471
22.2k
  return fxDatePrint4Digits(p, value);
1472
22.2k
}
1473
1474
txInteger fxDateSimilarYear(txInteger year)
1475
74.3k
{
1476
74.3k
  txInteger leap, day;
1477
74.3k
  if ((1970 <= year) && (year < 2038))
1478
15.4k
    return year;
1479
58.9k
  leap = mxIsLeapYear(year);
1480
58.9k
  year += mxYearsOffset - 1;
1481
58.9k
  day = mxYearDays(year) - mxYearDays(1970 + mxYearsOffset - 1);
1482
58.9k
  day = (day + 4) % 7;
1483
58.9k
  if (day < 0)
1484
35.6k
    day += 7; 
1485
58.9k
  return (leap) ? gxSimilarLeapYears[day] : gxSimilarCommonYears[day];
1486
74.3k
}
1487
1488
void fxDateSplit(txNumber value, txBoolean utc, txDateTime* dt)
1489
76.0k
{
1490
76.0k
  txInteger date, time, year, leap, month;
1491
76.0k
  const txInteger* monthsDays;
1492
76.0k
  date = (txInteger)c_trunc(value / mxDayMilliseconds);
1493
76.0k
  time = (txInteger)c_fmod(value, mxDayMilliseconds);
1494
76.0k
  if (time < 0) {
1495
15.0k
    date--;
1496
15.0k
    time += (txInteger)mxDayMilliseconds;
1497
15.0k
  }
1498
76.0k
  dt->offset = 0;
1499
76.0k
  dt->day = (date + 4) % 7;
1500
76.0k
  if (dt->day < 0)
1501
33.7k
    dt->day += 7; 
1502
76.0k
  dt->milliseconds = time % 1000;
1503
76.0k
  time /= 1000;
1504
76.0k
  dt->seconds = time % 60;
1505
76.0k
  time /= 60;
1506
76.0k
  dt->minutes = time % 60;
1507
76.0k
  time /= 60;
1508
76.0k
  dt->hours = time;
1509
76.0k
    date += mxYearDays(1970 + mxYearsOffset);
1510
76.0k
    year = 400 * (date / mx400YearsDays);
1511
76.0k
  date %= mx400YearsDays;
1512
76.0k
  date--;
1513
76.0k
  year += 100 * (date / mx100YearsDays);
1514
76.0k
  date %= mx100YearsDays;
1515
76.0k
  date++;
1516
76.0k
  year += 4 * (date / mx4YearsDays);
1517
76.0k
  date %= mx4YearsDays;
1518
76.0k
  date--;
1519
76.0k
  year += date / mx1YearDays;
1520
76.0k
    date %= mx1YearDays;
1521
76.0k
  year -= mxYearsOffset;
1522
76.0k
  leap = mxIsLeapYear(year);
1523
76.0k
    date += leap;
1524
76.0k
    monthsDays = leap ? gxLeapYearMonthsDays : gxCommonYearMonthsDays;
1525
412k
    for (month = 0; month < 11; month++) {
1526
410k
      if (date < monthsDays[month + 1])
1527
73.7k
        break;
1528
410k
    }
1529
76.0k
    date -= monthsDays[month];
1530
76.0k
  dt->date = date + 1;
1531
76.0k
  dt->month = month;
1532
76.0k
  dt->year = year;
1533
76.0k
  if (!utc) {
1534
24.8k
    txNumber former = value;
1535
24.8k
    txInteger similar;
1536
24.8k
    c_time_t time;
1537
24.8k
    c_tm tm;
1538
24.8k
    similar = fxDateSimilarYear(year);
1539
24.8k
    if (similar != year) {
1540
10.5k
      dt->year = similar;
1541
10.5k
      value = fxDateMerge(dt, 1);
1542
10.5k
    }
1543
24.8k
    time = (txInteger)c_floor(value / 1000.0);
1544
24.8k
    tm = *c_localtime(&time);
1545
24.8k
    dt->milliseconds = c_floor(c_fmod(value, 1000.0));
1546
24.8k
    dt->day = tm.tm_wday;
1547
24.8k
    dt->seconds = tm.tm_sec;
1548
24.8k
    dt->minutes = tm.tm_min;
1549
24.8k
    dt->hours = tm.tm_hour;
1550
24.8k
    dt->date = tm.tm_mday;
1551
24.8k
    dt->month = tm.tm_mon;
1552
24.8k
    dt->year = tm.tm_year + 1900 + year - similar;
1553
24.8k
    dt->offset = (txInteger)c_trunc((fxDateMerge(dt, 1) - former) / 60000.0);
1554
24.8k
  }
1555
76.0k
  dt->value = value;
1556
76.0k
}
1557
1558
1559
1560