1from ..base import * 2from .time_helpers import * 3 4TZ_OFFSET = (time.altzone // 3600) 5ABS_OFFSET = abs(TZ_OFFSET) 6TZ_NAME = time.tzname[1] 7ISO_FORMAT = '%s-%s-%sT%s:%s:%s.%sZ' 8 9 10@Js 11def Date(year, month, date, hours, minutes, seconds, ms): 12 return now().to_string() 13 14 15Date.Class = 'Date' 16 17 18def now(): 19 return PyJsDate(int(time.time() * 1000), prototype=DatePrototype) 20 21 22@Js 23def UTC(year, month, date, hours, minutes, seconds, ms): # todo complete this 24 args = arguments 25 y = args[0].to_number() 26 m = args[1].to_number() 27 l = len(args) 28 dt = args[2].to_number() if l > 2 else Js(1) 29 h = args[3].to_number() if l > 3 else Js(0) 30 mi = args[4].to_number() if l > 4 else Js(0) 31 sec = args[5].to_number() if l > 5 else Js(0) 32 mili = args[6].to_number() if l > 6 else Js(0) 33 if not y.is_nan() and 0 <= y.value <= 99: 34 y = y + Js(1900) 35 return TimeClip(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili))) 36 37 38@Js 39def parse(string): 40 return PyJsDate( 41 TimeClip(parse_date(string.to_string().value)), 42 prototype=DatePrototype) 43 44 45Date.define_own_property('now', { 46 'value': Js(now), 47 'enumerable': False, 48 'writable': True, 49 'configurable': True 50}) 51 52Date.define_own_property('parse', { 53 'value': parse, 54 'enumerable': False, 55 'writable': True, 56 'configurable': True 57}) 58 59Date.define_own_property('UTC', { 60 'value': UTC, 61 'enumerable': False, 62 'writable': True, 63 'configurable': True 64}) 65 66 67class PyJsDate(PyJs): 68 Class = 'Date' 69 extensible = True 70 71 def __init__(self, value, prototype=None): 72 self.value = value 73 self.own = {} 74 self.prototype = prototype 75 76 # todo fix this problematic datetime part 77 def to_local_dt(self): 78 return datetime.datetime(1970, 1, 1) + datetime.timedelta( 79 seconds=UTCToLocal(self.value) // 1000) 80 81 def to_utc_dt(self): 82 return datetime.datetime(1970, 1, 1) + datetime.timedelta( 83 seconds=self.value // 1000) 84 85 def local_strftime(self, pattern): 86 if self.value is NaN: 87 return 'Invalid Date' 88 try: 89 dt = self.to_local_dt() 90 except: 91 raise MakeError( 92 'TypeError', 93 'unsupported date range. Will fix in future versions') 94 try: 95 return dt.strftime(pattern) 96 except: 97 raise MakeError( 98 'TypeError', 99 'Could not generate date string from this date (limitations of python.datetime)' 100 ) 101 102 def utc_strftime(self, pattern): 103 if self.value is NaN: 104 return 'Invalid Date' 105 try: 106 dt = self.to_utc_dt() 107 except: 108 raise MakeError( 109 'TypeError', 110 'unsupported date range. Will fix in future versions') 111 try: 112 return dt.strftime(pattern) 113 except: 114 raise MakeError( 115 'TypeError', 116 'Could not generate date string from this date (limitations of python.datetime)' 117 ) 118 119 120def parse_date(py_string): # todo support all date string formats 121 try: 122 try: 123 dt = datetime.datetime.strptime(py_string, "%Y-%m-%dT%H:%M:%S.%fZ") 124 except: 125 dt = datetime.datetime.strptime(py_string, "%Y-%m-%dT%H:%M:%SZ") 126 return MakeDate( 127 MakeDay(Js(dt.year), Js(dt.month - 1), Js(dt.day)), 128 MakeTime( 129 Js(dt.hour), Js(dt.minute), Js(dt.second), 130 Js(dt.microsecond // 1000))) 131 except: 132 raise MakeError( 133 'TypeError', 134 'Could not parse date %s - unsupported date format. Currently only supported format is RFC3339 utc. Sorry!' 135 % py_string) 136 137 138def date_constructor(*args): 139 if len(args) >= 2: 140 return date_constructor2(*args) 141 elif len(args) == 1: 142 return date_constructor1(args[0]) 143 else: 144 return date_constructor0() 145 146 147def date_constructor0(): 148 return now() 149 150 151def date_constructor1(value): 152 v = value.to_primitive() 153 if v._type() == 'String': 154 v = parse_date(v.value) 155 else: 156 v = v.to_int() 157 return PyJsDate(TimeClip(v), prototype=DatePrototype) 158 159 160def date_constructor2(*args): 161 y = args[0].to_number() 162 m = args[1].to_number() 163 l = len(args) 164 dt = args[2].to_number() if l > 2 else Js(1) 165 h = args[3].to_number() if l > 3 else Js(0) 166 mi = args[4].to_number() if l > 4 else Js(0) 167 sec = args[5].to_number() if l > 5 else Js(0) 168 mili = args[6].to_number() if l > 6 else Js(0) 169 if not y.is_nan() and 0 <= y.value <= 99: 170 y = y + Js(1900) 171 t = TimeClip( 172 LocalToUTC(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili)))) 173 return PyJsDate(t, prototype=DatePrototype) 174 175 176Date.create = date_constructor 177 178DatePrototype = PyJsDate(float('nan'), prototype=ObjectPrototype) 179 180 181def check_date(obj): 182 if obj.Class != 'Date': 183 raise MakeError('TypeError', 'this is not a Date object') 184 185 186class DateProto: 187 def toString(): 188 check_date(this) 189 if this.value is NaN: 190 return 'Invalid Date' 191 offset = (UTCToLocal(this.value) - this.value) // msPerHour 192 return this.local_strftime( 193 '%a %b %d %Y %H:%M:%S GMT') + '%s00 (%s)' % (pad( 194 offset, 2, True), GetTimeZoneName(this.value)) 195 196 def toDateString(): 197 check_date(this) 198 return this.local_strftime('%d %B %Y') 199 200 def toTimeString(): 201 check_date(this) 202 return this.local_strftime('%H:%M:%S') 203 204 def toLocaleString(): 205 check_date(this) 206 return this.local_strftime('%d %B %Y %H:%M:%S') 207 208 def toLocaleDateString(): 209 check_date(this) 210 return this.local_strftime('%d %B %Y') 211 212 def toLocaleTimeString(): 213 check_date(this) 214 return this.local_strftime('%H:%M:%S') 215 216 def valueOf(): 217 check_date(this) 218 return this.value 219 220 def getTime(): 221 check_date(this) 222 return this.value 223 224 def getFullYear(): 225 check_date(this) 226 if this.value is NaN: 227 return NaN 228 return YearFromTime(UTCToLocal(this.value)) 229 230 def getUTCFullYear(): 231 check_date(this) 232 if this.value is NaN: 233 return NaN 234 return YearFromTime(this.value) 235 236 def getMonth(): 237 check_date(this) 238 if this.value is NaN: 239 return NaN 240 return MonthFromTime(UTCToLocal(this.value)) 241 242 def getDate(): 243 check_date(this) 244 if this.value is NaN: 245 return NaN 246 return DateFromTime(UTCToLocal(this.value)) 247 248 def getUTCMonth(): 249 check_date(this) 250 if this.value is NaN: 251 return NaN 252 return MonthFromTime(this.value) 253 254 def getUTCDate(): 255 check_date(this) 256 if this.value is NaN: 257 return NaN 258 return DateFromTime(this.value) 259 260 def getDay(): 261 check_date(this) 262 if this.value is NaN: 263 return NaN 264 return WeekDay(UTCToLocal(this.value)) 265 266 def getUTCDay(): 267 check_date(this) 268 if this.value is NaN: 269 return NaN 270 return WeekDay(this.value) 271 272 def getHours(): 273 check_date(this) 274 if this.value is NaN: 275 return NaN 276 return HourFromTime(UTCToLocal(this.value)) 277 278 def getUTCHours(): 279 check_date(this) 280 if this.value is NaN: 281 return NaN 282 return HourFromTime(this.value) 283 284 def getMinutes(): 285 check_date(this) 286 if this.value is NaN: 287 return NaN 288 return MinFromTime(UTCToLocal(this.value)) 289 290 def getUTCMinutes(): 291 check_date(this) 292 if this.value is NaN: 293 return NaN 294 return MinFromTime(this.value) 295 296 def getSeconds(): 297 check_date(this) 298 if this.value is NaN: 299 return NaN 300 return SecFromTime(UTCToLocal(this.value)) 301 302 def getUTCSeconds(): 303 check_date(this) 304 if this.value is NaN: 305 return NaN 306 return SecFromTime(this.value) 307 308 def getMilliseconds(): 309 check_date(this) 310 if this.value is NaN: 311 return NaN 312 return msFromTime(UTCToLocal(this.value)) 313 314 def getUTCMilliseconds(): 315 check_date(this) 316 if this.value is NaN: 317 return NaN 318 return msFromTime(this.value) 319 320 def getTimezoneOffset(): 321 check_date(this) 322 if this.value is NaN: 323 return NaN 324 return (this.value - UTCToLocal(this.value)) // 60000 325 326 def setTime(time): 327 check_date(this) 328 this.value = TimeClip(time.to_number().to_int()) 329 return this.value 330 331 def setMilliseconds(ms): 332 check_date(this) 333 t = UTCToLocal(this.value) 334 tim = MakeTime( 335 Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms) 336 u = TimeClip(LocalToUTC(MakeDate(Day(t), tim))) 337 this.value = u 338 return u 339 340 def setUTCMilliseconds(ms): 341 check_date(this) 342 t = this.value 343 tim = MakeTime( 344 Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms) 345 u = TimeClip(MakeDate(Day(t), tim)) 346 this.value = u 347 return u 348 349 def setSeconds(sec, ms=None): 350 check_date(this) 351 t = UTCToLocal(this.value) 352 s = sec.to_number() 353 if not ms is None: milli = Js(msFromTime(t)) 354 else: milli = ms.to_number() 355 date = MakeDate( 356 Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli)) 357 u = TimeClip(LocalToUTC(date)) 358 this.value = u 359 return u 360 361 def setUTCSeconds(sec, ms=None): 362 check_date(this) 363 t = this.value 364 s = sec.to_number() 365 if not ms is None: milli = Js(msFromTime(t)) 366 else: milli = ms.to_number() 367 date = MakeDate( 368 Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli)) 369 v = TimeClip(date) 370 this.value = v 371 return v 372 373 def setMinutes(min, sec=None, ms=None): 374 check_date(this) 375 t = UTCToLocal(this.value) 376 m = min.to_number() 377 if not sec is None: s = Js(SecFromTime(t)) 378 else: s = sec.to_number() 379 if not ms is None: milli = Js(msFromTime(t)) 380 else: milli = ms.to_number() 381 date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli)) 382 u = TimeClip(LocalToUTC(date)) 383 this.value = u 384 return u 385 386 def setUTCMinutes(min, sec=None, ms=None): 387 check_date(this) 388 t = this.value 389 m = min.to_number() 390 if not sec is None: s = Js(SecFromTime(t)) 391 else: s = sec.to_number() 392 if not ms is None: milli = Js(msFromTime(t)) 393 else: milli = ms.to_number() 394 date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli)) 395 v = TimeClip(date) 396 this.value = v 397 return v 398 399 def setHours(hour, min=None, sec=None, ms=None): 400 check_date(this) 401 t = UTCToLocal(this.value) 402 h = hour.to_number() 403 if not min is None: m = Js(MinFromTime(t)) 404 else: m = min.to_number() 405 if not sec is None: s = Js(SecFromTime(t)) 406 else: s = sec.to_number() 407 if not ms is None: milli = Js(msFromTime(t)) 408 else: milli = ms.to_number() 409 date = MakeDate(Day(t), MakeTime(h, m, s, milli)) 410 u = TimeClip(LocalToUTC(date)) 411 this.value = u 412 return u 413 414 def setUTCHours(hour, min=None, sec=None, ms=None): 415 check_date(this) 416 t = this.value 417 h = hour.to_number() 418 if not min is None: m = Js(MinFromTime(t)) 419 else: m = min.to_number() 420 if not sec is None: s = Js(SecFromTime(t)) 421 else: s = sec.to_number() 422 if not ms is None: milli = Js(msFromTime(t)) 423 else: milli = ms.to_number() 424 date = MakeDate(Day(t), MakeTime(h, m, s, milli)) 425 v = TimeClip(date) 426 this.value = v 427 return v 428 429 def setDate(date): 430 check_date(this) 431 t = UTCToLocal(this.value) 432 dt = date.to_number() 433 newDate = MakeDate( 434 MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t)) 435 u = TimeClip(LocalToUTC(newDate)) 436 this.value = u 437 return u 438 439 def setUTCDate(date): 440 check_date(this) 441 t = this.value 442 dt = date.to_number() 443 newDate = MakeDate( 444 MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t)) 445 v = TimeClip(newDate) 446 this.value = v 447 return v 448 449 def setMonth(month, date=None): 450 check_date(this) 451 t = UTCToLocal(this.value) 452 m = month.to_number() 453 if not date is None: dt = Js(DateFromTime(t)) 454 else: dt = date.to_number() 455 newDate = MakeDate( 456 MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t)) 457 u = TimeClip(LocalToUTC(newDate)) 458 this.value = u 459 return u 460 461 def setUTCMonth(month, date=None): 462 check_date(this) 463 t = this.value 464 m = month.to_number() 465 if not date is None: dt = Js(DateFromTime(t)) 466 else: dt = date.to_number() 467 newDate = MakeDate( 468 MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t)) 469 v = TimeClip(newDate) 470 this.value = v 471 return v 472 473 def setFullYear(year, month=None, date=None): 474 check_date(this) 475 if not this.value is NaN: t = UTCToLocal(this.value) 476 else: t = 0 477 y = year.to_number() 478 if not month is None: m = Js(MonthFromTime(t)) 479 else: m = month.to_number() 480 if not date is None: dt = Js(DateFromTime(t)) 481 else: dt = date.to_number() 482 newDate = MakeDate( 483 MakeDay(y, m, dt), TimeWithinDay(t)) 484 u = TimeClip(LocalToUTC(newDate)) 485 this.value = u 486 return u 487 488 def setUTCFullYear(year, month=None, date=None): 489 check_date(this) 490 if not this.value is NaN: t = UTCToLocal(this.value) 491 else: t = 0 492 y = year.to_number() 493 if not month is None: m = Js(MonthFromTime(t)) 494 else: m = month.to_number() 495 if not date is None: dt = Js(DateFromTime(t)) 496 else: dt = date.to_number() 497 newDate = MakeDate( 498 MakeDay(y, m, dt), TimeWithinDay(t)) 499 v = TimeClip(newDate) 500 this.value = v 501 return v 502 503 def toUTCString(): 504 check_date(this) 505 return this.utc_strftime('%d %B %Y %H:%M:%S') 506 507 def toISOString(): 508 check_date(this) 509 t = this.value 510 year = YearFromTime(t) 511 month, day, hour, minute, second, milli = pad( 512 MonthFromTime(t) + 1), pad(DateFromTime(t)), pad( 513 HourFromTime(t)), pad(MinFromTime(t)), pad( 514 SecFromTime(t)), pad(msFromTime(t)) 515 return ISO_FORMAT % (unicode(year) if 0 <= year <= 9999 else pad( 516 year, 6, True), month, day, hour, minute, second, milli) 517 518 def toJSON(key): 519 o = this.to_object() 520 tv = o.to_primitive('Number') 521 if tv.Class == 'Number' and not tv.is_finite(): 522 return this.null 523 toISO = o.get('toISOString') 524 if not toISO.is_callable(): 525 raise this.MakeError('TypeError', 'toISOString is not callable') 526 return toISO.call(o, ()) 527 528 529def pad(num, n=2, sign=False): 530 '''returns n digit string representation of the num''' 531 s = unicode(abs(num)) 532 if len(s) < n: 533 s = '0' * (n - len(s)) + s 534 if not sign: 535 return s 536 if num >= 0: 537 return '+' + s 538 else: 539 return '-' + s 540 541 542fill_prototype(DatePrototype, DateProto, default_attrs) 543 544Date.define_own_property( 545 'prototype', { 546 'value': DatePrototype, 547 'enumerable': False, 548 'writable': False, 549 'configurable': False 550 }) 551 552DatePrototype.define_own_property('constructor', { 553 'value': Date, 554 'enumerable': False, 555 'writable': True, 556 'configurable': True 557}) 558