Module pyfdate
[hide private]
[frames] | no frames]

Source Code for Module pyfdate

   1  """ 
   2  @version: 0.7 
   3  @date:    2008-08-28 
   4  @status:  beta 
   5  @author:  Stephen Ferg 
   6  @contact: http://www.ferg.org/contact_info 
   7  @license: Creative Commons Attribution License 2.0 http://creativecommons.org/licenses/by/2.0/ 
   8  @see:     http://www.ferg.org/pyfdate 
   9  @note: 
  10   
  11  ABOUT PYFDATE 
  12   
  13  The purpose of pyfdate is to provide a variety of user-friendly features 
  14  for working with datetimes, doing date arithmetic, and formatting dates, 
  15  times, and periods of time. 
  16   
  17  Pyfdate doesn't attempt to be all things to all people: rather, its goal 
  18  is to make it easy to do 95% if the things that people want to do with 
  19  dates and times. 
  20   
  21  Pyfdate provides two classes: 
  22   
  23  ------------------------------------------------------------------------ 
  24   
  25  Time: 
  26          - A specific point in time, identified by 
  27            year, month, day, hour, minute, second. 
  28          (Python's datetime module calls this a "datetime".) 
  29   
  30  Period: 
  31          - An amount of time, measured in days, hours, minutes, and seconds. 
  32   
  33  ------------------------------------------------------------------------ 
  34   
  35  In order to keep pyfdate simple, there are a number of things that it does not attempt to do. 
  36          - Pyfdate doesn't know anything about timezones. 
  37          - Pyfdate doesn't know anything about daylight savings time. 
  38          - Pyfdate doesn't provide any facilities for parsing strings into date/times. 
  39            (It does, however, provide a useful numsplit() function which performs a kind of parsing.) 
  40          - The smallest unit of time that Pyfdate can handle is a second. 
  41             It cannot be used to work with hundredths or thousandths of seconds. 
  42   
  43  INTERNATIONAL LANGUAGE SUPPORT 
  44   
  45  By default, pyfdate's language for displaying dates and times 
  46  (e.g. weekday names and month names) is American English. 
  47   
  48  If pyfdate can successfully import pyfdate_local, 
  49  the language for displaying dates and times 
  50  is taken from the pyfdate_local.py file. 
  51   
  52  Localization files are available for a number of languages. 
  53  For example: pyfdate_local_francais.py for French. 
  54   
  55  To use the file for language foobar, 
  56  simply copy pyfdate_local_foobar.py to pyfdate_local.py 
  57   
  58  And of course it is possible to customize pyfdate_local.py for any particular 
  59  language of your choice.  If you create (or correct) a localization file 
  60  for pyfdate, please share it with others by submitting it for inclusion 
  61  in the pyfdate distribution. 
  62   
  63   
  64  BACKGROUND 
  65   
  66  Many ideas for pyfdate functionality grew out of Steve Ferg's experiences with 
  67  an earlier (non-Python) program called "fdate", which provided datetime 
  68  arithmetic functionality for MS-DOS batch files. The name "pyfdate" is derived 
  69  from "Python" and "fdate". 
  70  """ 
  71  from pprint import pprint 
  72  import time, copy, sys, os, types 
  73   
  74  try: 
  75          import datetime 
  76  except ImportError, e: 
  77          raise AssertionError("Error importing datetime.\n" 
  78          +"Note that pyfdate requires Python version 2.3+.\n" 
  79          +"You are now running Python version " + sys.version) 
  80  from pprint import pprint 
  81   
  82  """ 
  83  Language-specific interface for pyfdate, for language:  American English 
  84  """ 
  85  LANG = "American English" 
  86  TimeExpressedIn24Hours = False 
  87  CivilTimeSeparator = ":" 
  88  CivilDateFormat = "m d, y"   # m=nameOfMonth  d=dayOfMonth y=year 
  89   
  90  HOUR    = "hour" 
  91  HOURS   = "hours" 
  92  MINUTE  = "minute" 
  93  MINUTES = "minutes" 
  94  SECOND  = "second" 
  95  SECONDS = "seconds" 
  96   
  97  DAY     = "day" 
  98  DAYS    = "days" 
  99  HOUR    = "hour" 
 100  HOURS   = "hours" 
 101  MINUTE  = "minute" 
 102  MINUTES = "minutes" 
 103  SECOND  = "second" 
 104  SECONDS = "seconds" 
 105   
 106  WEEK    = "week" 
 107  WEEKS   = "weeks" 
 108  MONTH   = "month" 
 109  MONTHS  = "months" 
 110  YEAR    = "year" 
 111  YEARS   = "years" 
 112   
 113  MONTH_NAMES = \ 
 114  { 1:"January" 
 115  , 2:"February" 
 116  , 3:"March" 
 117  , 4:"April" 
 118  , 5:"May" 
 119  , 6:"June" 
 120  , 7:"July" 
 121  , 8:"August" 
 122  , 9:"September" 
 123  ,10:"October" 
 124  ,11:"November" 
 125  ,12:"December" 
 126  } 
 127   
 128  WEEKDAY_NAMES = \ 
 129  {1:"Monday" 
 130  ,2:"Tuesday" 
 131  ,3:"Wednesday" 
 132  ,4:"Thursday" 
 133  ,5:"Friday" 
 134  ,6:"Saturday" 
 135  ,7:"Sunday" 
 136  } 
 137   
 138  #----------------------------------------------------------------------- 
 139  # make constants for month names and weekday names 
 140  # this may not work for all languages. (see below) 
 141  #----------------------------------------------------------------------- 
 142  for __monthNumber, __monthName in MONTH_NAMES.items(): 
 143          __monthName = __monthName.upper().replace("-","_") 
 144          exec(__monthName + " = " + str(__monthNumber)) 
 145   
 146  for __weekdayNumber, __weekdayName in WEEKDAY_NAMES.items(): 
 147          __weekdayName = __weekdayName.upper().replace("-","_") 
 148          exec(__weekdayName + " = " + str(__weekdayNumber)) 
 149   
 150  #----------------------------------------------------------------------- 
 151  # If a file called pyfdate_local exists, import it. 
 152  # This enables optional customization for different languages: 
 153  # German, French, Spanish, British English, etc. 
 154  #----------------------------------------------------------------------- 
 155  try: from pyfdate_local import * 
 156  except ImportError: pass 
 157   
 158  #--------------------------------------------------------------------- 
 159  #   set up some constants 
 160  #--------------------------------------------------------------------- 
 161  NEXT      = "NEXT" 
 162  NEAREST   = "NEAREST" 
 163  PREVIOUS  = "PREVIOUS" 
 164   
 165  SECONDS_IN_MINUTE  = 60 
 166  MINUTES_IN_HOUR    = 60 
 167  HOURS_IN_DAY       = 24 
 168  SECONDS_IN_HOUR    = SECONDS_IN_MINUTE * MINUTES_IN_HOUR 
 169  SECONDS_IN_DAY     = SECONDS_IN_HOUR   * HOURS_IN_DAY 
 170  MINUTES_IN_DAY     = MINUTES_IN_HOUR   * HOURS_IN_DAY 
 171   
 172  NORMAL_DAYS_IN_MONTH = \ 
 173          {  1:31 # JAN 
 174          ,  2:28 # FEB  # does not apply to leap years 
 175          ,  3:31 # MAR 
 176          ,  4:30 # APR 
 177          ,  5:31 # MAY 
 178          ,  6:30 # JUN 
 179          ,  7:31 # JUL 
 180          ,  8:31 # AUG 
 181          ,  9:30 # SEP 
 182          , 10:31 # OCT 
 183          , 11:30 # NOV 
 184          , 12:31 # DEC 
 185          } 
 186   
 187   
 188  #################################################################################### 
 189  # 
 190  #            class Period 
 191  # 
 192  #################################################################################### 
 193   
194 -class Period:
195 """ 196 A pyfdate.Period is an amount of time. 197 198 pyfdate.Period performs a function similar to the standard library datetime.timedelta. 199 pyfdate.Period, however, is implemented differently than the datetime.timedelta class. 200 pyfdate.Period stores only a single value: self.period_seconds. 201 This may be a positive or negative value. 202 203 pyfdate.Period objects (like datetime.timedelta objects) are used to do date 204 arithmetic. But since pyfdate.Time provides more sophisticated date 205 arithmetic features than datetime.datetime, pyfdate. Periods are probably 206 more widely used for their display capabilities than for their date 207 arithmetic capabilities. 208 """ 209 #----------------------------------------------------------------------------------- 210 # CONSTRUCTOR 211 #-----------------------------------------------------------------------------------
212 - def __init__(self, arg1=0,hours=0,minutes=0,seconds=0):
213 """ 214 Thhe constructor of a Period object. 215 216 Constructor expects arguments of: 217 - a series of positional arguments: [days [, hours[,minutes[,seconds]]]], or 218 - a datetime.timedelta object, or 219 - a pyfdate.Period object 220 @rtype: Period 221 """ 222 if isinstance(arg1, datetime.timedelta): 223 # first argument is a timedelta. Ignore the other args. 224 timedelta = arg1 225 self.period_seconds = timedelta.seconds + (timedelta.days * SECONDS_IN_DAY) 226 return 227 228 if isinstance(arg1, Period): 229 # first argument is a Period. Ignore the other args. 230 self.period_seconds = copy.deepcopy(arg1.period_seconds) 231 return 232 233 # else, arguments represent days, hours, minutes, seconds in a period. 234 days = arg1 235 self.period_seconds = ( 236 (days * SECONDS_IN_DAY ) 237 + (hours * SECONDS_IN_HOUR ) 238 + (minutes * SECONDS_IN_MINUTE) 239 + seconds )
240 241 242 #----------------------------------------------------------------------------------- 243 # __abs__ 244 #-----------------------------------------------------------------------------------
245 - def __abs__(self):
246 """ 247 Returns a clone of myself, with my absolute value. 248 @return: a clone of myself, with my absolute value 249 @rtype: Period 250 """ 251 return Period(0,0,0,abs(self.period_seconds))
252 253 #----------------------------------------------------------------------------------- 254 # __add__ 255 #-----------------------------------------------------------------------------------
256 - def __add__(self, arg):
257 """ 258 Add one period to another. 259 @return: a new Period object 260 @rtype: Period 261 """ 262 if isinstance(arg, Period): pass # no problem 263 else: 264 raise AssertionError("Cannot add a " 265 + arg.__class__.__name__ + " object to a Period object.") 266 267 return Period(0,0,0, self.period_seconds + arg.period_seconds)
268 269 #----------------------------------------------------------------------------------- 270 # comparison method 271 #-----------------------------------------------------------------------------------
272 - def __eq__(self,arg):
273 """ 274 Compare two Period objects for equality. 275 @rtype: boolean 276 """ 277 if isinstance(arg, Period): pass # no problem 278 else: 279 raise AssertionError("Cannot compare Period object with " 280 + arg.__class__.__name__ + " object.") 281 282 if self.period_seconds == arg.period_seconds: return True 283 return False
284 285 #----------------------------------------------------------------------------------- 286 # comparison method 287 #-----------------------------------------------------------------------------------
288 - def __ge__(self,arg):
289 """ 290 Compares two Period objects to determine if one is greater than, 291 or equal to, the other. 292 @rtype: boolean 293 """ 294 if self.__gt__(arg): return True 295 if self.__eq__(arg): return True 296 return False
297 298 #----------------------------------------------------------------------------------- 299 # comparison method 300 #-----------------------------------------------------------------------------------
301 - def __gt__(self,arg):
302 """ 303 Compares two Period objects to determine if one is greater than the other. 304 @rtype: boolean 305 """ 306 if isinstance(arg, Period): pass # no problem 307 else: 308 raise AssertionError("Cannot compare Period object with " 309 + arg.__class__.__name__ + " object.") 310 if self.period_seconds > arg.period_seconds: return True 311 return False
312 313 #----------------------------------------------------------------------------------- 314 # comparison method 315 #-----------------------------------------------------------------------------------
316 - def __le__(self,arg):
317 """ 318 Compares two Period objects to determine if one is less than, 319 or equal to, the other. 320 @rtype: boolean 321 """ 322 if self.__gt__(arg): return False 323 return True
324 325 #----------------------------------------------------------------------------------- 326 # comparison method 327 #-----------------------------------------------------------------------------------
328 - def __lt__(self,arg):
329 """ 330 Compares two Period objects to determine if one is less than the other. 331 @rtype: boolean 332 """ 333 if self.__gt__(arg): return False 334 if self.__eq__(arg): return False 335 return True
336 337 #----------------------------------------------------------------------------------- 338 # comparison method 339 #-----------------------------------------------------------------------------------
340 - def __neq__(self,arg):
341 """ 342 Compare two Period objects for inequality. 343 @rtype: boolean 344 """ 345 return not self.__eq__(arg)
346 347 #----------------------------------------------------------------------------------- 348 # __str__ 349 #-----------------------------------------------------------------------------------
350 - def __str__(self):
351 """ 352 Returns a string representation of a Period. 353 @rtype: string 354 @return: a string representation of a Period. 355 e.g.:: 356 "4 days 3 hours 20 minutes 45 seconds" 357 """ 358 return self.get_p()
359 360 361 #----------------------------------------------------------------------------------- 362 # __sub__ 363 #-----------------------------------------------------------------------------------
364 - def __sub__(self, arg):
365 """ 366 Subtract one period from another. 367 @return: a new Period object 368 @rtype: Period 369 """ 370 if isinstance(arg, Period): pass # no problem 371 else: 372 raise AssertionError("Cannot subtract a " 373 + arg.__class__.__name__ + " object from a Period object.") 374 375 return Period(0,0,0, self.period_seconds - arg.period_seconds)
376 377 378 #----------------------------------------------------------------------------------- 379 # subtract 380 #-----------------------------------------------------------------------------------
381 - def subtract(self, **kwargs):
382 """ 383 A general method for subtracting time from a Period object. 384 @rtype: Period 385 386 @note: Example: 387 :: 388 p1 = Period() 389 p2 = p1.plus(weeks=2,days=3,hours=4,minutes=99, seconds=1) 390 """ 391 for key,value in kwargs.items(): 392 kwargs[key] = value * -1 393 394 return self.add(**kwargs)
395 396 # minus() method is alias for subtract() method 397 minus = subtract 398 399 400 #----------------------------------------------------------------------------------- 401 # add 402 #-----------------------------------------------------------------------------------
403 - def add(self, **kwargs):
404 """ 405 A general method for adding time to a Period object. To 406 subtract time, add time in negative increments or use the subtract() method. 407 @rtype: Period 408 @note: 409 Example:: 410 p1 = Period() 411 p2 = p1.plus(weeks=2,days=3,hours=4,minutes=99, seconds=1) 412 """ 413 argNum = 0 414 p = self.clone() # p is a new Period object 415 for key, value in kwargs.items(): 416 argNum += 1 417 if False: pass 418 elif key in ("day" ,"days" , DAY , DAYS ): p = Period(0,0,0,p.period_seconds + (value * SECONDS_IN_DAY )) 419 elif key in ("hour" ,"hours" , HOUR , HOURS ): p = Period(0,0,0,p.period_seconds + (value * SECONDS_IN_HOUR )) 420 elif key in ("minute" ,"minutes", MINUTE, MINUTES): p = Period(0,0,0,p.period_seconds + (value * SECONDS_IN_MINUTE)) 421 elif key in ("second" ,"seconds", SECOND, SECONDS): p = Period(0,0,0,p.period_seconds + value ) 422 elif key in ("week" ,"weeks" , WEEK , WEEKS ): p = Period(0,0,0,p.period_seconds + (7*(value * SECONDS_IN_DAY))) 423 else : 424 raise AssertionError( 425 self.__class__.__name__ +".plus()" 426 + " received invalid keyword argument: " + str(key) 427 + " in argument " + str(argNum) + ".\n" 428 + kwargsToString(**kwargs) 429 ) 430 return p
431 432 # plus() method is alias for add() method 433 plus = add 434 435 #----------------------------------------------------------------------------------- 436 # clone 437 #-----------------------------------------------------------------------------------
438 - def clone(self):
439 """ 440 Return a clone of myself. 441 @return: a clone of myself 442 @rtype: Period 443 """ 444 return Period(0,0,0,self.period_seconds)
445 446 #----------------------------------------------------------------------------------- 447 # get_days 448 #-----------------------------------------------------------------------------------
449 - def get_days(self):
450 """ 451 Return the days portion of the period, as an int. 452 @rtype: int 453 @return: days, e.g.:: 454 3 455 """ 456 days, hours, minutes, seconds = self.get_tuple() 457 return days
458 days = property(get_days) 459 460 #----------------------------------------------------------------------------------- 461 # get_hours 462 #-----------------------------------------------------------------------------------
463 - def get_hours(self):
464 """ 465 Return the hours portion of the Period, as an int. 466 @rtype: int 467 @return: hours, e.g.:: 468 15 469 """ 470 days, hours, minutes, seconds = self.get_tuple() 471 return hours
472 hours = property(get_hours) 473 474 #----------------------------------------------------------------------------------- 475 # get_minutes 476 #-----------------------------------------------------------------------------------
477 - def get_minutes(self):
478 """ 479 Return the minutes portion of the Period, as an int. 480 @rtype: int 481 @return: minutes, e.g.:: 482 45 483 """ 484 days, hours, minutes, seconds = self.get_tuple() 485 return minutes
486 minutes = property(get_minutes) 487 488 #----------------------------------------------------------------------------------- 489 # get_seconds 490 #-----------------------------------------------------------------------------------
491 - def get_seconds(self):
492 """ 493 Return the seconds portion of the Period, as an int. 494 @rtype: int 495 @return: seconds, e.g.:: 496 45 497 """ 498 days, hours, minutes, seconds = self.get_tuple() 499 return seconds
500 seconds = property(get_seconds) 501 502 #----------------------------------------------------------------------------------- 503 # get_p 504 #-----------------------------------------------------------------------------------
505 - def get_p(self, **kwargs):
506 """ 507 Return myself in a nicely-formatted string. 508 @rtype: string 509 @return: myself in a nicely-formatted string, e.g.:: 510 "2 days 3 hours 0 minutes 45 seconds" 511 512 @note: 513 :: 514 if keyword arg showZeroComponents == True: 515 all components (days, hours, minutes, seconds) will be shown 516 else: 517 only non-zero components (except seconds) will be shown 518 519 if the period is empty (has a duration of zero): 520 if keyword arg showZeroPeriod == True: 521 return "0 seconds" 522 else: 523 return "" # the empty string 524 525 """ 526 showZeroComponents = kwargs.get("showZeroComponents",True) 527 showZeroPeriod = kwargs.get("showZeroPeriod",True) 528 529 if self.period_seconds == 0: 530 if showZeroPeriod: return "0 " + SECONDS 531 else: return "" 532 533 days, hours, minutes, seconds = self.get_tuple() 534 535 if days == 0 : 536 if showZeroComponents : daysString = "0 " + DAY 537 else : daystring = "" 538 elif days == 1 : daysString = "1 " + DAY 539 elif days == -1 : daysString = "-1 " + DAY 540 else : daysString = str(days) + " " + DAYS 541 542 if hours == 0 : 543 if showZeroComponents : hoursString = "0 " + HOURS 544 else : hoursString = "" 545 elif hours == 1 : hoursString = "1 " + HOUR 546 elif hours == -1 : hoursString = "-1 " + HOUR 547 else : hoursString = str(hours) + " " + HOURS 548 549 if minutes == 0: 550 if showZeroComponents : minutesString = "0 " + MINUTES 551 else : minutesString = "" 552 elif minutes == 1: minutesString = "1 " + MINUTE 553 else : minutesString = str(minutes) + " " + MINUTES 554 555 if seconds == 0: 556 if showZeroComponents : secondsString = "0 " + SECONDS 557 else : secondsString = "" 558 elif seconds == 1: secondsString = "1 " + SECOND 559 elif seconds ==-1: secondsString = "-1 " + SECOND 560 else : secondsString = str(seconds) + " " + SECONDS 561 562 results = "" 563 if showZeroComponents: 564 results += " " + daysString 565 results += " " + hoursString 566 results += " " + minutesString 567 results += " " + secondsString 568 else: 569 if days : results += " " + daysString 570 if hours : results += " " + hoursString 571 if minutes: results += " " + minutesString 572 if seconds: results += " " + secondsString 573 574 return results.strip()
575 576 p = property(get_p) 577 578 579 #----------------------------------------------------------------------------------- 580 # get_short 581 #-----------------------------------------------------------------------------------
582 - def get_short(self):
583 """ 584 Return myself as a nicely formatted string: suppress components whose value is zero. 585 @rtype: string 586 @return: myself nicely formatted: suppress components whose value is zero. 587 If my duration is zero, return "0 seconds". e.g.:: 588 "2 days 3 hours" 589 @note: This method will never return an empty string. 590 If my duration is zero, then it returns the string "0 seconds" 591 """ 592 return self.get_p(showZeroComponents=False)
593 short = property(get_short) 594 595 #----------------------------------------------------------------------------------- 596 # get_shortest 597 #-----------------------------------------------------------------------------------
598 - def get_shortest(self):
599 """ 600 Return myself as a nicely formatted string: suppress components whose value is zero. 601 @rtype: string 602 @return: myself nicely formatted: suppress components whose value is zero. 603 e.g.:: 604 "2 days 3 hours" 605 @note: If my duration is 0, this method will return an empty string. 606 """ 607 return self.get_p(showZeroComponents=False,showZeroPeriod=False)
608 shortest = property(get_shortest) 609 610 #----------------------------------------------------------------------------------- 611 # get_timedelta 612 #-----------------------------------------------------------------------------------
613 - def get_timedelta(self):
614 """ 615 Returns a Period expressed as a datetime.timedelta object 616 @return: a Period expressed as a datetime.timedelta object 617 @rtype: timedelta 618 """ 619 days, seconds = divmod(self.period_seconds, SECONDS_IN_DAY) 620 return datetime.timedelta(days, seconds)
621 timedelta = property(get_timedelta) 622 623 624 #----------------------------------------------------------------------------------- 625 # get_tuple 626 #-----------------------------------------------------------------------------------
627 - def get_tuple(self):
628 """ 629 Returns myself formatted as a 4-tuple of ints (days, hours, minutes, seconds). 630 @return: myself formatted as a 4-tuple of ints (days, hours, minutes, seconds) 631 @rtype: tuple 632 """ 633 period_seconds = abs(self.period_seconds) 634 635 days , remainder = divmod(period_seconds, SECONDS_IN_DAY) 636 hours , remainder = divmod(remainder , SECONDS_IN_HOUR) 637 minutes, seconds = divmod(remainder , SECONDS_IN_MINUTE) 638 639 if self.period_seconds >= 0: 640 return days, hours, minutes, seconds 641 else: # self.period_seconds is negative 642 return -days, -hours, -minutes, -seconds
643 644 tuple = property(get_tuple) 645 646 647 #----------------------------------------------------------------------------------- 648 # get_asDays 649 #-----------------------------------------------------------------------------------
650 - def get_asDays(self):
651 """ 652 Returns this Period, expressed in units of days. 653 @return: myself, expressed in units of days 654 @rtype: int 655 """ 656 days, seconds = divmod(abs(self.period_seconds), SECONDS_IN_DAY) 657 return days
658 asDays = property(get_asDays) 659 660 #----------------------------------------------------------------------------------- 661 # get_asHours 662 #-----------------------------------------------------------------------------------
663 - def get_asHours(self):
664 """ 665 Returns this Period, expressed in units of hours. 666 @return: myself, expressed in units of hours 667 @rtype: int 668 """ 669 hours, seconds = divmod(abs(self.period_seconds), SECONDS_IN_HOUR) 670 return hours
671 asHours = property(get_asHours) 672 673 #----------------------------------------------------------------------------------- 674 # get_asMinutes 675 #-----------------------------------------------------------------------------------
676 - def get_asMinutes(self):
677 """ 678 Returns this Period, expressed in units of minutes. 679 @return: myself, expressed in units of minutes 680 @rtype: int 681 """ 682 minutes, seconds = divmod(abs(self.period_seconds), SECONDS_IN_MINUTE) 683 return minutes
684 asMinutes = property(get_asMinutes) 685 686 #----------------------------------------------------------------------------------- 687 # get_asSeconds 688 #-----------------------------------------------------------------------------------
689 - def get_asSeconds(self):
690 """ 691 Returns this Period, expressed in units of seconds. 692 @return: myself, expressed in units of seconds 693 @rtype: int 694 """ 695 return abs(self.period_seconds)
696 asSeconds = property(get_asSeconds)
697 698 #----------------------------------------------------------------------------------- 699 # end of class definition for Period 700 #----------------------------------------------------------------------------------- 701 702 703 #################################################################################### 704 #################################################################################### 705 # 706 # class: Time 707 # 708 #################################################################################### 709 #################################################################################### 710 711
712 -class Time:
713 """ 714 A specific point in time, identified by 715 year, month, day, hour, minute, second. 716 717 Python's datetime module calls this a "datetime". 718 """ 719 720 #----------------------------------------------------------------------------------- 721 # CONSTRUCTOR 722 #-----------------------------------------------------------------------------------
723 - def __init__(self,arg1=None,month=1,day=1,hour=0,minute=0,second=0):
724 """ 725 The constructor for a Time object. 726 727 Constructor expects arguments of: 728 - None (this will construct a Time object from current date/time) or 729 - a datetime.datetime object, or 730 - a pyfdate.Time object, or 731 - a series of positional arguments: year [,month[,day[,hour[,minute[,second]]]]] 732 @rtype: Time 733 """ 734 if arg1==None: 735 # we use the current datetime 736 self.datetime = datetime.datetime.now() 737 return 738 739 if isinstance(arg1, datetime.datetime): 740 # first argument is a datatime.datetime object. 741 # Use it, and ignore all other arguments. 742 self.datetime = copy.deepcopy(arg1) 743 return 744 745 if isinstance(arg1,Time): 746 # first argument is a Time object. 747 # Use it, and ignore all other arguments. 748 self.datetime = copy.deepcopy(arg1.datetime) 749 return 750 751 # else... 752 year = arg1 753 try: 754 self.datetime = datetime.datetime(year,month,day,hour,minute,second) 755 except ValueError, e: 756 raise ValueError(str(e) + "\nArgs to Time.__init__ were:\n" 757 + str(arg1) + "\n" 758 + str(month) + "\n" 759 + str(day) + "\n" 760 + str(hour) + "\n" 761 + str(minute) + "\n" 762 + str(second) + "\n" 763 )
764 765 #----------------------------------------------------------------------------------- 766 # __add__ 767 #-----------------------------------------------------------------------------------
768 - def __add__(self, arg):
769 """ 770 Add a Period to this Time to produce a new Time. 771 @rtype: Time 772 """ 773 if isinstance(arg, Period): 774 return Time(self.datetime + arg.timedelta) 775 776 raise AssertionError("Cannot add a " 777 + arg.__class__.__name__ + " object to a Time object.")
778 779 #----------------------------------------------------------------------------------- 780 # comparison methods - the basics 781 #-----------------------------------------------------------------------------------
782 - def __eq__(self,arg):
783 """ 784 Compare two Time objects for equality. 785 @rtype: boolean 786 """ 787 if isinstance(arg, Time): pass # no problem 788 else: raise AssertionError("Cannot compare a " 789 + arg.__class__.__name__ + " object to a Time object.") 790 791 if self.datetime == arg.datetime: return True 792 return False
793 794 #----------------------------------------------------------------------------------- 795 # comparison method 796 #-----------------------------------------------------------------------------------
797 - def __ge__(self,arg):
798 """ 799 Compare two Time objects for relative position in time. 800 @rtype: boolean 801 """ 802 if self.__gt__(arg): return True 803 if self.__eq__(arg): return True 804 return False
805 806 #----------------------------------------------------------------------------------- 807 # comparison method 808 #-----------------------------------------------------------------------------------
809 - def __gt__(self,arg):
810 """ 811 Compare two Time objects to determine if one is later (greater than) the other. 812 @rtype: boolean 813 """ 814 if isinstance(arg, Time): pass # no problem 815 else: raise AssertionError("Cannot compare a " 816 + arg.__class__.__name__ + " object to a Time object.") 817 818 if self.datetime > arg.datetime: return True 819 return False
820 821 #----------------------------------------------------------------------------------- 822 # comparison method 823 #-----------------------------------------------------------------------------------
824 - def __le__(self,arg):
825 """ 826 Compare two Time objects for relative position in time. 827 @rtype: boolean 828 """ 829 if self.__gt__(arg): return False 830 return True
831 832 #----------------------------------------------------------------------------------- 833 # comparison method 834 #-----------------------------------------------------------------------------------
835 - def __lt__(self,arg):
836 """ 837 Compare two Time objects for relative position in time. 838 @rtype: boolean 839 """ 840 if self.__gt__(arg): return False 841 if self.__eq__(arg): return False 842 return True
843 844 #----------------------------------------------------------------------------------- 845 # comparison method 846 #-----------------------------------------------------------------------------------
847 - def __neq__(self,arg):
848 """ 849 Compare two Time objects for inequality. 850 @rtype: boolean 851 """ 852 return not self.__eq__(arg)
853 854 855 #----------------------------------------------------------------------------------- 856 # __str__ 857 #-----------------------------------------------------------------------------------
858 - def __str__(self):
859 """ 860 Return a string representation of self as an isodate + space + isotime 861 @rtype: string 862 @return: self as an isodate + space + isotime, e.g.:: 863 "2007-03-02 09:30:45" 864 """ 865 return self.get_isodatetime(" ")
866 867 868 #----------------------------------------------------------------------------------- 869 # __sub__ 870 #-----------------------------------------------------------------------------------
871 - def __sub__(self, arg):
872 """ 873 Subtract a Period or a Time from this Time object. 874 875 @rtype: Time or Period 876 @return: a Time (if <arg> is a Period) or a Period (if <arg> is a Time) 877 878 @arg arg: a Period object or a Time object 879 @type arg: Period or Time 880 881 @note: 882 :: 883 If <arg> is a Period object: 884 Subtract a Period from this Time to produce a new Time, 885 else, if <arg> is a Time object: 886 Subtract one Time from another Time to produce a Period. 887 888 @note: 889 If a Period is returned, it is signed. That is:: 890 If an earlier time is subtracted from a later time: 891 The Period will be positive 892 else: 893 the Period will be negative. 894 """ 895 if isinstance(arg, Time): 896 timedelta = self.datetime - arg.datetime 897 return Period(timedelta) 898 899 if isinstance(arg, Period): 900 return Time(self.datetime - arg.timedelta) 901 902 raise AssertionError("Cannot subtract a " 903 + arg.__class__.__name__ + " object from a Time object.")
904 905 906 #----------------------------------------------------------------------------------- 907 # add 908 #-----------------------------------------------------------------------------------
909 - def add(self, **kwargs):
910 """ 911 A method to add time to a Time object. 912 This is the basic method for doing date/time arithmetic. 913 914 The units and amounts of time are specified as keyword arguments. 915 916 @rtype: Time 917 @return: a new Time object with the specified amounts of time added to it. 918 919 @note: To subtract amounts, you can add negative amounts (see the example) 920 or use the 'subtract' method. 921 922 @note: Example: To get the time that is a month and a week from the current time:: 923 t = Time().add(months=1,weeks=1) 924 @note: Example: To get the time that is a month and a week from the current time:: 925 t = Time().add(months=1).plus(weeks=1) 926 927 @note: Example: To subtract 6 weeks from the current time:: 928 t = Time().add(weeks=-6) # note the minus sign: -6. 929 """ 930 days, hours, minutes, seconds = 0, 0.0, 0.0, 0.0 931 932 t = self.clone() 933 p = Period() 934 for key, value in kwargs.items(): 935 if False: pass 936 elif key in ("day" ,"days" , DAY , DAYS ): p = p.add(days=value) 937 elif key in ("hour" ,"hours" , HOUR , HOURS ): p = p.add(hours=value) 938 elif key in ("minute" ,"minutes", MINUTE, MINUTES): p = p.add(minutes=value) 939 elif key in ("second" ,"seconds", SECOND, SECONDS): p = p.add(seconds=value) 940 elif key in ("week" ,"weeks" , WEEK , WEEKS ): p = p.add(weeks=value) 941 elif key in ("month" ,"months" , MONTH , MONTHS ): t = t.addmonths(value) 942 elif key in ("year" ,"years" , YEAR , YEARS ): t = t.addmonths(value * 12) 943 else: 944 raise AssertionError("In Time.plus() method, " 945 + "I do not recognize keyword " 946 + key +" in argment: " 947 + key + "=" + str(value) 948 ) 949 return t + p
950 951 #----------------------------------------------------------------------------------- 952 # plus 953 #----------------------------------------------------------------------------------- 954 # plus() method is alias for add() method 955 plus = add 956 957 958 #----------------------------------------------------------------------------------- 959 # addmonths 960 #-----------------------------------------------------------------------------------
961 - def addmonths(self, months):
962 """ 963 A method for adding months to a time object. 964 965 >>> t1 = Time(2004,1,31) 966 >>> t1.d 967 'January 31, 2004' 968 >>> t2 = t1.addmonths(1) 969 >>> t2.d 970 'February 29, 2004' 971 >>> t2 = t1.add(months=8) 972 >>> t2.d 973 'September 30, 2004' 974 975 @rtype: Time 976 @return: a new Time object with the specified amounts of time added to it. 977 978 @note: 979 You can use this method directly, e.g.:: 980 t = Time().addmonths(6) 981 982 Or you can use the standard add() method:: 983 t = Time().add(months=6) 984 """ 985 numericMonth = CalendarMonthToNumericMonth(self.year, self.month) 986 numericMonth += months 987 newYear, newMonth = NumericMonthToCalendarMonth(numericMonth) 988 989 maxDaysInNewMonth = NORMAL_DAYS_IN_MONTH[newMonth] 990 if newMonth == 2 and isLeapYear(newYear): maxDaysInNewMonth += 1 991 992 newDay = self.day 993 if self.day > maxDaysInNewMonth: 994 # We have moved to a new month that is shorter than the month where we 995 # started, and have run off the end of the month. 996 # We need to back up to the last day in the new month. 997 newDay = maxDaysInNewMonth 998 999 return Time(newYear,newMonth,newDay,self.hour,self.minute,self.second)
1000 1001 1002 #----------------------------------------------------------------------------------- 1003 # anniversary 1004 #-----------------------------------------------------------------------------------
1005 - def anniversaryOf(self, eventTime):
1006 """ 1007 The most recent anniversary of myself. 1008 @return: The most recent anniversary of some event, previous to today. 1009 @rtype: Time 1010 @arg eventTime: the time of the event whose anniversary we want 1011 @type eventTime: Time 1012 @note: In a non-leapyear, the anniversary of an event that occurred 1013 on February 29 of a leapyear will be moved to February 28. 1014 """ 1015 # get eventAnniversaryThisYear 1016 eventAnniversaryThisYear = eventTime.goto(year=self.year) 1017 1018 # if the event anniversary has not yet occurred in this year, 1019 # use the anniversary that occurred last year 1020 if eventAnniversaryThisYear <= self: 1021 return eventAnniversaryThisYear 1022 else: 1023 return eventTime.goto(year=self.year-1)
1024 1025 1026 #----------------------------------------------------------------------------------- 1027 # clone 1028 #-----------------------------------------------------------------------------------
1029 - def clone(self, **kwargs):
1030 """ 1031 Return a clone of myself. 1032 @return: a clone of myself 1033 @rtype: Time 1034 1035 @note: 1036 It is possible to change certain parts of the cloned Time 1037 by using keyword arguments for the component(s) to 1038 be replaced in the clone. To make a clone of the current 1039 time, but one set in the year 1935, for example:: 1040 t1 = Time() 1041 t2 = t1.clone(year=1935) 1042 1043 Note that it is possible to trigger a ValueError, if 1044 for example: 1045 - The current date is February 29, 2004 (a leap year) and the 1046 year is reset to 2007 (not a leap year). 1047 - The current date is January 31 and the month is reset to 1048 September (which has only 30 days). 1049 1050 If you *want* to raise a ValueError when such problems occur, 1051 use the clone() method. Otherwise, use the goto() method, 1052 which attempts to recover from such errors:: 1053 t1 = Time() 1054 t2 = t1.goto(year=1935) 1055 """ 1056 year,month,day,hour,minute,second = self.get_tuple() 1057 1058 for key, value in kwargs.items(): 1059 if value == int(value): pass 1060 else: 1061 raise AssertionError("In Time.clone() method, keyword argment: " 1062 + key + "=" + str(value) 1063 + "\nthe argument value is not an int." 1064 ) 1065 1066 if False: pass 1067 elif key in ("year" , YEAR ): year = value 1068 elif key in ("month" , MONTH ): month = value 1069 elif key in ("day" , DAY ): day = value 1070 elif key in ("hour" , HOUR ): hour = value 1071 elif key in ("minute" , MINUTE): minute = value 1072 elif key in ("second" , SECOND): second = value 1073 else: 1074 raise AssertionError("In Time.clone() method, " 1075 + "I do not recognize keyword " 1076 + key +" in argment: " 1077 + key + "=" + str(value) 1078 ) 1079 return Time(year,month,day,hour,minute,second)
1080 1081 1082 #----------------------------------------------------------------------------------- 1083 # diff 1084 #-----------------------------------------------------------------------------------
1085 - def diff(self, eventTime):
1086 """ 1087 Determine the difference (a Period) between two Times. 1088 @rtype: Period 1089 @note: 1090 Unlike the __sub__ method, the diff (i.e. difference) method 1091 always returns a Period object with a positive value. 1092 """ 1093 if isinstance(eventTime, Time): pass 1094 else: 1095 raise AssertionError("Expecting a Time object as argument. Found a " 1096 + eventTime.__class__.__name__ + " object.") 1097 1098 timedelta = self.datetime - eventTime.datetime 1099 return Period( abs(timedelta) )
1100 1101 1102 1103 #----------------------------------------------------------------------------------- 1104 # diffyears 1105 #-----------------------------------------------------------------------------------
1106 - def diffyears(self, eventTime):
1107 """ 1108 Determine the difference (a Period) between myself and the time of some event. 1109 @rtype: tuple 1110 @note: 1111 returns the difference between two Time objects as a tuple of 1112 (years, Period) 1113 """ 1114 if isinstance(eventTime, Time): pass 1115 else: 1116 raise AssertionError("Expecting a Time object as argument. Found a " 1117 + eventTime.__class__.__name__ + " object.") 1118 1119 laterTime = self 1120 earlierTime = eventTime 1121 1122 if earlierTime > laterTime: 1123 laterTime, earlierTime = earlierTime, laterTime 1124 1125 anniversaryTime = laterTime.anniversaryOf(earlierTime) 1126 1127 elapsedYears = anniversaryTime.year - earlierTime.year 1128 periodSinceAnniversary = laterTime - anniversaryTime 1129 1130 return elapsedYears, periodSinceAnniversary
1131 1132 diffy = diffyears 1133 1134 1135 #----------------------------------------------------------------------------------- 1136 # diffyearsmonths 1137 #-----------------------------------------------------------------------------------
1138 - def diffyearsmonths(self, eventTime):
1139 """ 1140 Determine the difference (a Period) between myself and the time of some event. 1141 @rtype: tuple 1142 @note: 1143 returns the difference between two Time objects as a tuple of 1144 (years,months, Period) 1145 """ 1146 if isinstance(eventTime, Time): pass 1147 else: 1148 raise AssertionError("Expecting a Time object as argument. Found a " 1149 + eventTime.__class__.__name__ + " object.") 1150 1151 years, days = self.diffmonths(eventTime) 1152 years, months = divmod(years,12) 1153 return years, months, days
1154 diffym = diffyearsmonths 1155 1156 #----------------------------------------------------------------------------------- 1157 # diffmonths 1158 #-----------------------------------------------------------------------------------
1159 - def diffmonths(self, eventTime):
1160 """ 1161 Determine the difference (a Period) between myself and the time of some event. 1162 @rtype: tuple 1163 @examle: 1164 Returns the difference between two Time objects as a tuple of 1165 (months, Period), so the Period part can be formatted as desired:: 1166 personDateOfBirth = Time(1946,5,8,6,45) 1167 months, days = Time().diffm(personDateOfBirth) 1168 print ("He is " + str(months) + " " + str(days) + " old.") 1169 1170 """ 1171 if isinstance(eventTime, Time): pass 1172 else: 1173 raise AssertionError("Expecting a Time object as argument. Found a " 1174 + eventTime.__class__.__name__ + " object.") 1175 1176 laterTime = self 1177 earlierTime = eventTime 1178 1179 if earlierTime > laterTime: 1180 laterTime, earlierTime = earlierTime, laterTime 1181 1182 anniversaryTime = earlierTime.goto(year=laterTime.year,month=laterTime.month) 1183 # if the event anniversary has not yet occurred in this month, 1184 # use the anniversary that occurred last year 1185 if anniversaryTime <= laterTime: pass 1186 else: 1187 lastMonth = laterTime.minus(months=1) 1188 anniversaryTime = earlierTime.goto(year=lastMonth.year,month=lastMonth.month) 1189 1190 1191 earlierNumericMonth = CalendarMonthToNumericMonth(earlierTime.year, earlierTime.month) 1192 anniversaryNumericMonth = CalendarMonthToNumericMonth(anniversaryTime.year, anniversaryTime.month) 1193 elapsedMonths = anniversaryNumericMonth - earlierNumericMonth 1194 1195 periodSinceAnniversary = laterTime - anniversaryTime 1196 1197 return elapsedMonths, periodSinceAnniversary
1198 1199 diffm = diffmonths 1200 1201 1202 #----------------------------------------------------------------------------------- 1203 # exitWeekend 1204 #-----------------------------------------------------------------------------------
1205 - def exitWeekend(self, direction=None):
1206 """ 1207 return a new Time object which has been moved so it does not fall 1208 on a Saturday or Sunday. 1209 1210 @rtype: Time 1211 @type direction: string 1212 1213 @arg direction: the direction in which to exit the weekend:: 1214 @note: 1215 If the weekday of the current object occurs on the weekend, the 1216 weekday of the new object is moved out of the weekend:: 1217 if <direction> is NEXT , the day is moved to the following Monday. 1218 if <direction> is PREVIOUS, the day is moved to the previous Friday. 1219 if <direction> is None , then 1220 - a Saturday is moved to the previous Friday 1221 - a Sunday is moved to the following Monday 1222 """ 1223 if self.weekday == 6: # SATURDAY 1224 if direction == NEXT: return self.add(days=2) 1225 return self.add(days=-1) 1226 1227 elif self.weekday == 7: # SUNDAY 1228 if direction == PREVIOUS: return self.add(days=-2) 1229 return self.add(days=1) 1230 1231 else: 1232 return self.clone()
1233 1234 1235 1236 #----------------------------------------------------------------------------------- 1237 # flex 1238 #-----------------------------------------------------------------------------------
1239 - def flex(self, baseTime):
1240 """ 1241 A method for adding days to a date, based on a base date. If the 1242 day-of-month of my time is less than the day-of-month of the baseTime, 1243 then calculate the number of days difference and add them to my time. 1244 1245 This method is designed to be used when doing monthly arithmetic. 1246 In the following example, we add 1 month to January 31. Because 1247 February contains only 28 days, we get February 28. 1248 1249 If we want to get the counterpart of January 31 in February 1250 (February 31, which resolves to March 3) we can "flex" the 1251 date based on the base date of January 31. 1252 1253 >>> startDate = Time(2003,1,31) 1254 >>> startDate.d 1255 'January 31, 2003' 1256 >>> startDate.add(months=1).d 1257 'February 28, 2003' 1258 >>> startDate.add(months=1).flex(startDate).d 1259 'March 3, 2003' 1260 1261 @rtype: Time 1262 @return: a new Time object that has been "flexed" based on the baseTime 1263 """ 1264 if baseTime.day > self.day: 1265 number_of_lost_days = baseTime.day - self.day 1266 return self.add(days=number_of_lost_days) 1267 else: 1268 return self
1269 1270 1271 #----------------------------------------------------------------------------------- 1272 # fromFile 1273 #-----------------------------------------------------------------------------------
1274 - def fromFile(self, filename):
1275 """ 1276 @return: a new Time object with the datetime of the last modification 1277 date of the file with <filename>. 1278 @rtype: Time 1279 @arg filename: a filename 1280 @type filename: string 1281 """ 1282 timestamp = os.path.getmtime(filename) 1283 return self.fromTimestamp(timestamp)
1284 1285 1286 #----------------------------------------------------------------------------------- 1287 # fromTimestamp 1288 #-----------------------------------------------------------------------------------
1289 - def fromTimestamp(self, timestamp):
1290 """ 1291 @return: a new Time object with the datetime from <timestamp>. 1292 @rtype: Time 1293 @arg timestamp: a timestamp 1294 @type timestamp: timestamp 1295 @see: the datetime module for documentation 1296 """ 1297 return Time(datetime.datetime.fromtimestamp(timestamp))
1298 1299 #----------------------------------------------------------------------------------- 1300 # get_civildate 1301 #-----------------------------------------------------------------------------------
1302 - def get_civildate(self):
1303 """ 1304 Return a string containing the civildate. 1305 @rtype: string 1306 @return: the civildate, e.g.:: 1307 "April 30, 2007" 1308 """ 1309 return self.get_d()
1310 civildate = property(get_civildate) 1311 1312 #----------------------------------------------------------------------------------- 1313 # __getCiviltimeBase 1314 #-----------------------------------------------------------------------------------
1315 - def __getCiviltimeBase(self, **kwargs):
1316 """ 1317 A utility method for other civiltime methods. 1318 @rtype: tuple 1319 @return: a tuple containing the components of civiltime:: 1320 (hour, minute, second, am_pm_flag) 1321 """ 1322 if TimeExpressedIn24Hours: 1323 return self.hour,self.minute,self.second,"" 1324 1325 # else, fall thru to return time express as am/pm 1326 1327 am = kwargs.get("am", "am") 1328 pm = kwargs.get("pm", "pm") 1329 1330 hour = self.hour 1331 if self.hour == 0: hour = 12 1332 elif self.hour > 12: hour = self.hour -12 1333 1334 if self.hour < 12: return hour,self.minute,self.second,am 1335 else: return hour,self.minute,self.second,pm
1336 1337 civiltimebase = property(__getCiviltimeBase) 1338 1339 1340 #----------------------------------------------------------------------------------- 1341 # get_civiltime 1342 #-----------------------------------------------------------------------------------
1343 - def get_civiltime(self, **kwargs):
1344 """ 1345 Return a string containing the civil time. 1346 1347 If keyword arg showseconds=True, time will include seconds. 1348 1349 If keyword arg showHundredthsOfSeconds=True, time will include hundredths of seconds. 1350 1351 Note that hundredths of seconds are faked to "00". 1352 This is primarily for MS-DOS timestamps which show hundredths of seconds, 1353 even though the clocks of PCs are not accurate to hundredths of seconds. 1354 1355 @rtype: string 1356 @return: a string containing the civil time, e.g.:: 1357 "6:30pm" 1358 1359 @note: 1360 Civil time as used in United States of America:: 1361 midnight = 12:00am 1362 time between midnight and noon = am 1363 noon = 12:00pm 1364 time between noon and midnight = am 1365 1366 @type showseconds: boolean 1367 @keyword showseconds: defaults to False. 1368 1369 @type showHundredthsOfSeconds: boolean 1370 @keyword showHundredthsOfSeconds: defaults to False. 1371 """ 1372 showseconds = kwargs.get("showseconds", False) 1373 showHundredthsOfSeconds = kwargs.get("showHundredthsOfSeconds", False) 1374 1375 if showHundredthsOfSeconds: showseconds = True 1376 1377 hour, minute,second,ampm = self.__getCiviltimeBase(**kwargs) 1378 1379 result = str(hour) + CivilTimeSeparator + str(minute).zfill(2) 1380 if showseconds: result += CivilTimeSeparator + str(second).zfill(2) 1381 if showHundredthsOfSeconds: result = result + CivilTimeSeparator + "00" 1382 1383 return result + ampm # for 24hour time, ampm = ""
1384 1385 1386 civiltime = property(get_civiltime) 1387 t = property(get_civiltime) 1388 1389 #----------------------------------------------------------------------------------- 1390 # get_civiltime2 1391 #-----------------------------------------------------------------------------------
1392 - def get_civiltime2(self):
1393 """ 1394 Return a string containing the civil time (including seconds.) 1395 @rtype: string 1396 @return: a string containing the civil time including seconds, 1397 e.g.:: 1398 "6:30:45pm" 1399 """ 1400 return self.get_civiltime(showseconds=True)
1401 civiltime2 = property(get_civiltime2) 1402 t2 = property(get_civiltime2) 1403 1404 #----------------------------------------------------------------------------------- 1405 # get_d 1406 #-----------------------------------------------------------------------------------
1407 - def get_d(self):
1408 """ 1409 Return a string containing the civildate. 1410 @rtype: string 1411 @return: the civildate, e.g.:: 1412 "April 30, 2007" 1413 """ 1414 result = [] 1415 for character in CivilDateFormat: 1416 if character == "m": result.append(self.monthname) 1417 elif character == "d": result.append(str(self.day)) 1418 elif character == "y": result.append(str(self.year)) 1419 else : result.append(character) 1420 return "".join(result)
1421 1422 d = property(get_d) # d = date = civildate 1423 1424 1425 #----------------------------------------------------------------------------------- 1426 # get_dostime 1427 #-----------------------------------------------------------------------------------
1428 - def get_dostime(self):
1429 """ 1430 Return the datetime in the format used by Microsoft's MS-DOS. 1431 @rtype: string 1432 @return: the datetime in the format used by Microsoft's MS-DOS 1433 """ 1434 return self.get_civiltime(am="a",pm="p",showHundredthsOfSeconds=True)
1435 dostime = property(get_dostime) 1436 1437 1438 #----------------------------------------------------------------------------------- 1439 # get_day 1440 #-----------------------------------------------------------------------------------
1441 - def get_day(self):
1442 """ 1443 Return the day part of the datetime. 1444 @return: day 1445 @rtype: int 1446 """ 1447 return self.datetime.day
1448 day = property(get_day) 1449 1450 1451 #----------------------------------------------------------------------------------- 1452 # get_dt 1453 #-----------------------------------------------------------------------------------
1454 - def get_dt(self):
1455 """ 1456 Return a string containing the civildate and the time, e.g. "April 30, 2007 6:30pm". 1457 @rtype: string 1458 @return: the civildate and the time, e.g.:: 1459 "April 30, 2007 6:30pm" 1460 """ 1461 return self.d + " " + self.civiltime
1462 dt = property(get_dt) # wdt = weekdayname, date, time 1463 1464 #----------------------------------------------------------------------------------- 1465 # get_dt2 1466 #-----------------------------------------------------------------------------------
1467 - def get_dt2(self):
1468 """ 1469 Return a string containing the civildate and the time (including seconds) 1470 e.g. "April 30, 2007 6:30:45pm". 1471 1472 @rtype: string 1473 @return: the civildate and the time, e.g.:: 1474 "April 30, 2007 6:30:45pm" 1475 """ 1476 return self.d + " " + self.civiltime2
1477 dt2 = property(get_dt2) # dt = date, time (including seconds) 1478 1479 #----------------------------------------------------------------------------------- 1480 # get_hour 1481 #-----------------------------------------------------------------------------------
1482 - def get_hour(self):
1483 """ 1484 Return the hour portion of the Time, as an int. 1485 @return: hour 1486 @rtype: int 1487 """ 1488 return self.datetime.hour
1489 hour = property(get_hour) 1490 1491 1492 #----------------------------------------------------------------------------------- 1493 # get_isodate 1494 #-----------------------------------------------------------------------------------
1495 - def get_isodate(self,sep="-"):
1496 """ 1497 Return a string containing an ISO date in format yyyy-mm-dd, e.g. "2007-10-09" 1498 @rtype: string 1499 @return: an ISO date in format yyyy-mm-dd, e.g.:: 1500 "2007-10-09" # Oct 9, 2007 1501 1502 @type sep: string 1503 @arg sep: separator string to use. Defaults to the ISO standard: a dash. 1504 """ 1505 return ( 1506 str(self.year).zfill(4) 1507 + sep 1508 + str(self.month).zfill(2) 1509 + sep 1510 + str(self.day).zfill(2) 1511 )
1512 isodate = property(get_isodate) 1513 1514 #----------------------------------------------------------------------------------- 1515 # get_isotime 1516 #-----------------------------------------------------------------------------------
1517 - def get_isotime(self,sep=":"):
1518 """ 1519 Return a string containing ISO time in format hh:mm:ss, e.g. "11:15:00". 1520 @rtype: string 1521 @return: an ISO time in format hh:mm:ss, e.g.:: 1522 "11:15:00" # 11:15 in the morning 1523 1524 @type sep: string 1525 @arg sep: separator string to use. Defaults to the ISO standard: a colon. 1526 """ 1527 return ( 1528 str(self.hour).zfill(2) 1529 + sep 1530 + str(self.minute).zfill(2) 1531 + sep 1532 + str(self.second).zfill(2) 1533 )
1534 isotime = property(get_isotime) 1535 1536 #----------------------------------------------------------------------------------- 1537 # get_isodatetime 1538 #-----------------------------------------------------------------------------------
1539 - def get_isodatetime(self,sep="T",datesep="-",timesep=":",seps=None):
1540 """ 1541 Return a string containing an ISO datetime in format yyyy-mm-ddThh:mm:ss. 1542 @rtype: string 1543 @return: an ISO datetime in format yyyy-mm-ddThh:mm:ss, e.g.:: 1544 "2007-10-09T11:15:00" # Oct 9, 2007 at 11:15 in the morning 1545 1546 @type sep: string 1547 @arg sep: separator string to use between date and time. 1548 Default is the ISO standard, a capital letter "T". 1549 @arg datesep: separator string to use within date. 1550 Default is the ISO standard, a dash "-". 1551 @arg timesep: separator string to use within time. 1552 Default is the ISO standard, a colon ":". 1553 @arg seps: separator string to use within and between date and time. 1554 If specified, seps over-rides the other separators. 1555 Note that the value for seps may be a zero-length string. 1556 "seps" is useful for constructing datetime strings for things like 1557 datestamps and filenames. 1558 """ 1559 if seps != None: 1560 sep = datesep = timesep = seps 1561 return self.get_isodate(sep=datesep) + sep + self.get_isotime(sep=timesep)
1562 isodatetime = property(get_isodatetime) 1563 1564 #----------------------------------------------------------------------------------- 1565 # get_isofilename 1566 #-----------------------------------------------------------------------------------
1567 - def get_isofilename(self,sep="-"):
1568 """ 1569 Return a string containing the ISO datetime in a format suitable for making a filename. 1570 @rtype: string 1571 @return: the ISO datetime in a format suitable for making a filename. E.g.:: 1572 "2007-10-09-11-15-00" # Oct 9, 2007 at 11:15 in the morning 1573 1574 @note: All parts of the datetime will be separated by dashes. 1575 @note: A collection of these strings, sorted using a standard string sort, 1576 will sort in temporal order. 1577 1578 @type sep: string 1579 @arg sep: separator string to use between datetime parts. Default = "-" 1580 """ 1581 return self.get_isodate(sep) + sep + self.get_isotime(sep)
1582 isofilename = property(get_isofilename) 1583 1584 1585 #----------------------------------------------------------------------------------- 1586 # get_isoweekday 1587 #-----------------------------------------------------------------------------------
1588 - def get_isoweekday(self):
1589 """ 1590 Return the ISO weekday number as an int, where Monday=1 .. Sunday=7 1591 @rtype: int 1592 @return: the ISO weekday number, e.g.:: 1593 1 # first day of the week, Monday 1594 """ 1595 return self.datetime.isoweekday()
1596 isoweekday = property(get_isoweekday) 1597 weekday = property(get_isoweekday) 1598 1599 1600 #----------------------------------------------------------------------------------- 1601 # get_isoweeknumber 1602 #-----------------------------------------------------------------------------------
1603 - def get_isoweeknumber(self):
1604 """ 1605 Return the ISO week number, as an int. 1606 @rtype: int 1607 @return: the ISO week number, e.g.:: 1608 1 # first week of the year 1609 """ 1610 year, weeknumber, weekday = self.datetime.isocalendar() 1611 return weeknumber
1612 weeknumber = property(get_isoweeknumber) 1613 isoweeknumber = property(get_isoweeknumber) 1614 1615 #----------------------------------------------------------------------------------- 1616 # get_minute 1617 #-----------------------------------------------------------------------------------
1618 - def get_minute(self):
1619 """ 1620 Return the minute portion of a Time, as an int. 1621 @rtype: int 1622 @return: minute, e.g.:: 1623 15 # 15 minutes past the beginning of the hour 1624 """ 1625 return self.datetime.minute
1626 minute = property(get_minute) 1627 1628 1629 #----------------------------------------------------------------------------------- 1630 # get_month 1631 #-----------------------------------------------------------------------------------
1632 - def get_month(self):
1633 """ 1634 Return the month portion of a Time, as an int. 1635 @rtype: int 1636 @return: month, e.g.:: 1637 12 # for the 12th month, December 1638 """ 1639 return self.datetime.month
1640 month = property(get_month) 1641 1642 1643 #----------------------------------------------------------------------------------- 1644 # get_monthname 1645 #-----------------------------------------------------------------------------------
1646 - def get_monthname(self):
1647 """ 1648 Return a string containing the natural language name of the month. 1649 @rtype: string 1650 @return: monthname, e.g.:: 1651 "December" 1652 """ 1653 return MONTH_NAMES[self.month]
1654 monthname = property(get_monthname) 1655 m = property(get_monthname) 1656 1657 1658 #----------------------------------------------------------------------------------- 1659 # get_second 1660 #-----------------------------------------------------------------------------------
1661 - def get_second(self):
1662 """ 1663 Return the second portion of a Time, as an int. 1664 @return: second 1665 @rtype: int 1666 """ 1667 return self.datetime.second
1668 second = property(get_second) 1669 1670 1671 #----------------------------------------------------------------------------------- 1672 # get_td 1673 #-----------------------------------------------------------------------------------
1674 - def get_td(self):
1675 """ 1676 Return a string containing the time and the civil date. 1677 @rtype: string 1678 @return: the time and the civildate, e.g.:: 1679 "6:30pm April 30, 2007" 1680 """ 1681 return self.civiltime + " " + self.d
1682 td = property(get_td) # td = time and date 1683 1684 1685 1686 #----------------------------------------------------------------------------------- 1687 # get_t2d 1688 #-----------------------------------------------------------------------------------
1689 - def get_t2d(self):
1690 """ 1691 Return a string containing the time and the civil date 1692 (including seconds). 1693 @rtype: string 1694 @return: the time and the civildate, e.g.:: 1695 "6:30:45pm April 30, 2007" 1696 """ 1697 return self.civiltime2 + " " + self.d
1698 t2d = property(get_t2d) # t=time, d=date 1699 1700 #----------------------------------------------------------------------------------- 1701 # get_tuple 1702 #-----------------------------------------------------------------------------------
1703 - def get_tuple(self):
1704 """ 1705 Return a tuple containing the parts of the datetime. 1706 @rtype: tuple 1707 @return: myself formatted as a 6-tuple of ints (year, month, day, hour, minute, second). 1708 E.g.:: 1709 (2007,10,9,11,15,0) # Oct 9, 2007 at 11:15 in the morning 1710 """ 1711 return self.year,self.month,self.day,self.hour,self.minute,self.second
1712 1713 1714 #----------------------------------------------------------------------------------- 1715 # get_twd 1716 #-----------------------------------------------------------------------------------
1717 - def get_twd(self):
1718 """ 1719 Return a string containing the time, the weekday name, and the civildate. 1720 @rtype: string 1721 @return: the time, the weekday name, and the civildate, e.g.:: 1722 "6:30pm Monday April 30, 2007" 1723 """ 1724 return self.civiltime + " " + self.weekdayname + " " + self.d
1725 twd = property(get_twd) # twd = time, weekdayname, and date 1726 1727 1728 #----------------------------------------------------------------------------------- 1729 # get_t2wd 1730 #-----------------------------------------------------------------------------------
1731 - def get_t2wd(self):
1732 """ 1733 Return a string containing the time (including seconds), 1734 the weekday name, and the civildate. 1735 @rtype: string 1736 @return: the time (including seconds), the weekday name, and the civildate, e.g.:: 1737 "6:30:45pm Monday April 30, 2007" 1738 """ 1739 return self.civiltime2 + " " + self.weekdayname + " " + self.d
1740 t2wd = property(get_t2wd) # twd = time, weekdayname, and date 1741 1742 #----------------------------------------------------------------------------------- 1743 # get_unixdate 1744 #-----------------------------------------------------------------------------------
1745 - def get_unixdate(self,sep="-"):
1746 """ 1747 Return a string containing a Unix date, e.g. "07-DEC-2006". 1748 @rtype: string 1749 @return: a string containing a Unix date, e.g.:: 1750 "07-DEC-2006" 1751 1752 @type sep: string 1753 @arg sep: separator string to use. Defaults to a dash. 1754 """ 1755 return ( 1756 str(self.day).zfill(2) 1757 + sep 1758 + self.monthname.upper()[:3] 1759 + sep 1760 + str(self.year).zfill(4) 1761 )
1762 unixdate = property(get_unixdate) 1763 1764 #----------------------------------------------------------------------------------- 1765 # get_weekdayname 1766 #-----------------------------------------------------------------------------------
1767 - def get_weekdayname(self, weekday=None):
1768 """ 1769 Returns the natural language name of the day of the week. 1770 @rtype: string 1771 @return: the natural language name of the day of the week, e.g.:: 1772 "Monday" 1773 1774 @type weekday: int 1775 @arg weekday: the ISO weekday number. If not specified, defaults 1776 to the weekday of self (this Time object). 1777 """ 1778 if weekday: return WEEKDAY_NAMES[weekday] 1779 return WEEKDAY_NAMES[self.weekday]
1780 1781 weekdayname = property(get_weekdayname) 1782 w = property(get_weekdayname) 1783 1784 1785 #----------------------------------------------------------------------------------- 1786 # get_wd 1787 #-----------------------------------------------------------------------------------
1788 - def get_wd(self):
1789 """ 1790 Returns a string containing the weekday name and the civildate. 1791 @rtype: string 1792 @return: the weekday name and the civildate. 1793 e.g.:: 1794 "Monday April 30, 2007" 1795 """ 1796 return self.weekdayname + " " + self.d
1797 wd = property(get_wd) # wd = weekdayname and date 1798 1799 1800 #----------------------------------------------------------------------------------- 1801 # get_wdt 1802 #-----------------------------------------------------------------------------------
1803 - def get_wdt(self):
1804 """ 1805 Returns a string containing the weekday name, the civildate, and the time. 1806 @rtype: string 1807 @return: the weekday name, the civildate, and the time, e.g.:: 1808 "Monday April 30, 2007 6:30pm" 1809 """ 1810 return self.weekdayname + " " + self.d + " " + self.civiltime
1811 wdt = property(get_wdt) # wdt = weekdayname, date, time 1812 1813 #----------------------------------------------------------------------------------- 1814 # get_wdt2 1815 #-----------------------------------------------------------------------------------
1816 - def get_wdt2(self):
1817 """ 1818 Returns a string containing the weekday name, the civildate, 1819 and the time (including seconds). 1820 @rtype: string 1821 @return: the weekday name, the civildate, and the time, e.g.:: 1822 "Monday April 30, 2007 6:30:45pm" 1823 """ 1824 return self.weekdayname + " " + self.d + " " + self.civiltime2
1825 wdt2 = property(get_wdt2) # w=weekday, d=date, t2=time(including seconds) 1826 1827 #----------------------------------------------------------------------------------- 1828 # get_year 1829 #-----------------------------------------------------------------------------------
1830 - def get_year(self):
1831 """ 1832 Return the year as an int, e.g. 2007 1833 @rtype: int 1834 @return: year, e.g.:: 1835 2007 1836 """ 1837 return self.datetime.year
1838 year = property(get_year) 1839 1840 1841 #----------------------------------------------------------------------------------- 1842 # get_yearstring 1843 #-----------------------------------------------------------------------------------
1844 - def get_yearstring(self):
1845 """ 1846 Return the year as a string, e.g. "2007" 1847 @rtype: string 1848 @return: year, 1849 e.g.:: 1850 "2007" 1851 """ 1852 return str(self.datetime.year)
1853 y = property(get_yearstring) 1854 1855 1856 1857 #----------------------------------------------------------------------------------- 1858 # goto 1859 #-----------------------------------------------------------------------------------
1860 - def goto(self,**kwargs):
1861 """ 1862 Returns a clone of self but with some component(s) 1863 (year, month, day, hour, minute, second) reset to a new value. 1864 1865 @rtype: Time 1866 @return: a new Time object in which the time has been moved 1867 according to the keyword args 1868 1869 @note: 1870 A "goto" can fail in a number of ways. 1871 - The current date is February 29, 2004 (a leap year) and the 1872 year is reset to 2007 (not a leap year). 1873 - The current date is January 31 and the month is reset to 1874 September (which has only 30 days). 1875 @note: This method attempts to recover from such failures by decrementing 1876 the "day" value to 28 before failing. 1877 1878 @note: Example: 1879 To obtain a Time object whose date is May 15, 2003:: 1880 t = Time(2007,5,15) 1881 t2 = t.goto(year=2003) 1882 1883 @note: Example: 1884 To obtain a time object whose date is February 28, 2007:: 1885 t = Time(2004,2,29) # a leap year 1886 t2 = t.goto(year=2007) # not a leap year 1887 """ 1888 year = kwargs.get("year",self.year) 1889 month = kwargs.get("month",self.month) 1890 day = kwargs.get("day",self.day) 1891 1892 # adjust to normal days in month 1893 if day > NORMAL_DAYS_IN_MONTH[month]: 1894 day = NORMAL_DAYS_IN_MONTH[month] 1895 1896 # possible adjustment to February 29 1897 possible_day = day 1898 while month == 2 and (possible_day == 28 or possible_day == 29): 1899 try: 1900 return Time(year,month, possible_day 1901 , kwargs.get("hour",self.hour) 1902 , kwargs.get("minute",self.minute) 1903 , kwargs.get("second",self.second) 1904 ) 1905 except ValueError: pass 1906 possible_day = possible_day -1 1907 1908 # fall thru to attempt to do the original move 1909 return Time(year,month,day 1910 , kwargs.get("hour",self.hour) 1911 , kwargs.get("minute",self.minute) 1912 , kwargs.get("second",self.second) 1913 )
1914 1915 1916 #----------------------------------------------------------------------------------- 1917 # gotoMonth 1918 #-----------------------------------------------------------------------------------
1919 - def gotoMonth(self, argMonth, direction=NEXT, **kwargs):
1920 """ 1921 Returns a new Time object in which the month has been moved to the specified 1922 argMonth. 1923 1924 @rtype: Time 1925 @return: a new Time object in which the month has been moved to the specified 1926 month number. 1927 1928 @type argMonth: int 1929 @arg argMonth: 1930 The argMonth number should be specified by means 1931 of one of pyfdate's month number constants (JANUARY, FEBRUARY, etc.) 1932 1933 @type direction: string 1934 @arg direction: The direction in time:: 1935 If direction == NEXT , we will move forward in time to the following month 1936 If direction == PREVIOUS, we will move backward in time to the preceding month 1937 If direction == NEAREST , we will move to the nearest month 1938 1939 @type useToday: boolean 1940 @keyword useToday: 1941 If the current month is the same as argMonth, the value of the 1942 useToday flag (True or False) will determine whether or not we use 1943 the current month, or ignore it, in our search for the NEXT, PREVIOUS, or NEAREST month. 1944 1945 @note: Example: 1946 If this month is April, to move the date to the following November:: 1947 t = Time().gotoMonth(NOVEMBER) 1948 or 1949 t = Time().gotoMonth(NOVEMBER,NEXT) 1950 1951 @note: Example: 1952 If this month is April, to move the date to the previous November:: 1953 t = Time().gotoMonth(NOVEMBER, PREVIOUS) 1954 1955 1956 @note: Example: 1957 If this month is April, to move the date to the nearest November:: 1958 t = Time().gotoMonth(NOVEMBER, NEAREST) 1959 1960 @note: 1961 Question:: 1962 If today is in November and we want to go to the NEXT (or PREVIOUS) November, 1963 is today considered to be in the next (or previous) November? 1964 Answer:: 1965 If useToday == True: (which is the default) 1966 today is considered to be in the nearest November. 1967 else: (useToday=False has been specified as a keyword arg) 1968 today is ignored in determining the NEXT (or PREVIOUS) November. 1969 1970 Question:: 1971 If today is November and we want to go to the NEAREST November 1972 and we have specified useToday=False, 1973 which is the nearest November: last November or next November? 1974 Answer:: 1975 NEXT (i.e. the future) November is considered nearest. 1976 """ 1977 useToday = kwargs.get("useToday", True) 1978 1979 if direction == NEAREST : return self.__gotoNearestMonth(argMonth,useToday) 1980 elif direction == NEXT : increment = +1 1981 elif direction == PREVIOUS: increment = -1 1982 else: 1983 raise AssertionError("Invalid argument for direction: " + str(direction)) 1984 1985 m = CalendarMonthToNumericMonth(self.year, self.month) 1986 newYear, newMonth = NumericMonthToCalendarMonth(m) 1987 1988 if self.month == argMonth: 1989 if useToday: 1990 return self.clone() 1991 else: 1992 # ignore today and move one month in the increment direction 1993 m += increment 1994 newYear, newMonth = NumericMonthToCalendarMonth(m) 1995 1996 while newMonth != argMonth: 1997 m += increment 1998 newYear, newMonth = NumericMonthToCalendarMonth(m) 1999 2000 newTime = Time(newYear, newMonth, self.day, self.hour, self.minute, self.second) 2001 return newTime
2002 2003 #----------------------------------------------------------------------------------- 2004 # gotoMonthBegin 2005 #-----------------------------------------------------------------------------------
2006 - def gotoMonthBegin(self):
2007 """ 2008 Return a new Time object in which the time has been moved to the beginning of the month. 2009 @rtype: Time 2010 @return: a new Time object in which the time has been moved to the beginning of the month. 2011 @note: 2012 Example: 2013 If today is May 15, 2007 then to obtain a time object whose date is May 1:: 2014 t = Time().gotoMonthBegin() 2015 """ 2016 return Time(self.year, self.month, 1, self.hour, self.minute, self.second)
2017 2018 #----------------------------------------------------------------------------------- 2019 # gotoMonthEnd 2020 #-----------------------------------------------------------------------------------
2021 - def gotoMonthEnd(self):
2022 """ 2023 Return a new Time object in which the time has been moved to the end of the month. 2024 @rtype: Time 2025 @return: a new Time object in which the time has been moved to the end of the month. 2026 2027 @note: Example: 2028 If today is May 15, 2007 then to obtain a time object whose date is May 31:: 2029 t = Time().gotoMonthEnd() 2030 """ 2031 # we move to the beginning of this month, 2032 # then add a month so that we're at the beginning of next month, 2033 # then subtract a day so we're at the end of this month. 2034 2035 return self.gotoMonthBegin().plus(months=1,days=-1)
2036 2037 #----------------------------------------------------------------------------------- 2038 # gotoYearBegin 2039 #-----------------------------------------------------------------------------------
2040 - def gotoYearBegin(self):
2041 """ 2042 Return a new Time object in which the time has been moved to the beginning of year. 2043 @rtype: Time 2044 @return: a new Time object in which the time has been moved to the beginning of year. 2045 @note: Example: 2046 If today is May 15, 2007 then to obtain a time object whose date is January 1, 2007:: 2047 t = Time().gotoYearBegin() 2048 """ 2049 return Time(self.year, 1,1, self.hour,self.minute,self.second)
2050 2051 #----------------------------------------------------------------------------------- 2052 # gotoYearEnd 2053 #-----------------------------------------------------------------------------------
2054 - def gotoYearEnd(self):
2055 """ 2056 Return a new Time object in which the time has been moved to the end of the year. 2057 @rtype: Time 2058 @return: a new Time object in which the time has been moved to the end of the year. 2059 @note: Example: 2060 If today is May 15, 2007 then to obtain a time object whose date is December 31, 2007:: 2061 t = Time().gotoYearEnd() 2062 """ 2063 # move to January 1 of next year, then backtrack by one day 2064 return Time(self.year+1, 1,1, self.hour,self.minute,self.second).plus(days=-1)
2065 2066 #----------------------------------------------------------------------------------- 2067 # __gotoNearestMonth 2068 #-----------------------------------------------------------------------------------
2069 - def __gotoNearestMonth(self, month, useTodayFlag):
2070 """ 2071 Return a new Time object in which the month has been moved 2072 (forward or backward) to the closest month with month number <month>. 2073 2074 @rtype: Time 2075 @return: 2076 a new Time object in which the month has been moved 2077 (forward or backward) to the closest month with month number <month>. 2078 2079 @type month: int 2080 @arg month: the monthnumber of the the desired month. 2081 The monthnumber should be specified by means 2082 of one of pyfdate's month number constants. 2083 2084 @type useTodayFlag: boolean 2085 @arg useTodayFlag: specifies what to do it the current monthnumber is 2086 the same as the desired monthnumber:: 2087 If useTodayFlag == True: 2088 return the current month 2089 else: 2090 return the month one year in the future. 2091 2092 @note: 2093 If the NEXT month with monthnumber <month> 2094 and the PREVIOUS month with monthnumber <month> 2095 are both exactly six months from the current month, 2096 then return the NEXT month with monthnumber <month>. 2097 2098 @note: Example: 2099 t = Time().__gotoNearestMonth(JULY) 2100 """ 2101 if self.month == month: 2102 if useTodayFlag: 2103 return self.clone() 2104 else: 2105 return self.add(years=1) 2106 2107 else: 2108 timeNext = self.gotoMonth(month, NEXT , useToday=False) 2109 timePrev = self.gotoMonth(month, PREVIOUS, useToday=False) 2110 2111 monthnumSelf = CalendarMonthToNumericMonth(self.year, self.month) 2112 monthnumNext = CalendarMonthToNumericMonth(timeNext.year, timeNext.month) 2113 monthnumPrev = CalendarMonthToNumericMonth(timePrev.year, timePrev.month) 2114 2115 futureDifference = abs(monthnumSelf - monthnumNext) 2116 pastDifference = abs(monthnumSelf - monthnumPrev) 2117 2118 if futureDifference <= pastDifference: return timeNext 2119 else: return timePrev
2120 2121 2122 #----------------------------------------------------------------------------------- 2123 # __gotoNearestWeekday 2124 #-----------------------------------------------------------------------------------
2125 - def __gotoNearestWeekday(self, weekday, useTodayFlag):
2126 """ 2127 Return a new Time object in which the weekday has been moved 2128 (forward or backward) to the closest weekday with weekday number <weekday>. 2129 2130 @note: 2131 If the current weekday is already <weekday>:: 2132 if useToday == False 2133 return the NEXT <weekday> 2134 else 2135 return a clone of the current Time object. 2136 2137 @rtype: Time 2138 @note: 2139 <weekday> should be specified by means 2140 of one of pyfdate's weekday number constants. 2141 2142 @note: Example:: 2143 t = Time().movetoNearestWeekday(THURSDAY) 2144 """ 2145 if self.weekday == weekday: 2146 if useTodayFlag: 2147 return self.clone() 2148 else: 2149 return self.add(weeks=1) 2150 2151 else: 2152 futureWeekday = self.gotoWeekday(weekday, NEXT) 2153 pastWeekday = self.gotoWeekday(weekday, PREVIOUS) 2154 2155 futureDifference = futureWeekday - self 2156 pastDifference = self - pastWeekday 2157 2158 if futureDifference <= pastDifference: return futureWeekday 2159 else: return pastWeekday
2160 2161 #----------------------------------------------------------------------------------- 2162 # gotoWeekday 2163 #-----------------------------------------------------------------------------------
2164 - def gotoWeekday(self, argWeekday, direction=NEXT, **kwargs):
2165 """ 2166 Return a new Time object in which 2167 the date has been moved to the specified argWeekday. 2168 2169 @rtype: Time 2170 @return: a new Time object in which the time has been moved to the specified weekday. 2171 2172 @type argWeekday: int 2173 @arg argWeekday: 2174 The argWeekday number should be specified by means 2175 of one of pyfdate's weekday number constants (MONDAY, TUESDAY, etc.) 2176 2177 @type direction: string 2178 @arg direction: The direction in time:: 2179 If direction == NEXT , we will move forward in time to the following weekday 2180 If direction == PREVIOUS, we will move backward in time to the preceding weekday 2181 If direction == NEAREST , we will move to the nearest weekday 2182 2183 @type useToday: boolean 2184 @keyword useToday: 2185 If the current weekday is the same as argWeekday, the value of the 2186 useToday flag (True or False) will determine whether we use the current date, 2187 or ignore it, in our search for the NEXT, PREVIOUS, or NEAREST weekday. 2188 """ 2189 """ 2190 2191 @note: 2192 Example: 2193 If today is Tuesday:: 2194 t = Time().gotoWeekday(THURSDAY) 2195 or 2196 t = Time().gotoWeekday(THURSDAY,NEXT) 2197 will move the date to the following Thursday. 2198 2199 @note: 2200 Example: 2201 If today is Tuesday:: 2202 t = Time().gotoWeekday(THURSDAY, PREVIOUS) 2203 will move the date to the previous Thursday. 2204 2205 @note: 2206 Example: 2207 t = Time().gotoWeekday(THURSDAY,NEAREST) 2208 will move the date to the nearest Thursday. 2209 2210 @note: 2211 Question: If today is Thursday and we want to go to the NEXT (or PREVIOUS) Thursday: 2212 Is today considered to be the next (or previous) Thursday? 2213 2214 Answer:: 2215 If useToday == True: (which is the default) 2216 today is considered the nearest Thursday. 2217 else: (useToday=False has been specified as a keyword arg) 2218 today is ignored in determining the NEXT (or PREVIOUS) Thursday. 2219 2220 Question: if today is Thursday and we want to go to the NEAREST Thursday 2221 and we have specified useToday=False: 2222 Which is the nearest Thursday: last Thursday or next Thursday? 2223 Answer: 2224 NEXT (i.e. the future) Thursday is considered nearest. 2225 """ 2226 useToday = kwargs.get("useToday", True) 2227 2228 if direction == NEAREST : return self.__gotoNearestWeekday(argWeekday, useToday) 2229 elif direction == NEXT : increment = +1 2230 elif direction == PREVIOUS: increment = -1 2231 else: 2232 raise AssertionError("Invalid argument for direction: " + str(direction)) 2233 2234 if self.weekday == argWeekday: 2235 if useToday: 2236 return self.clone() 2237 else: 2238 return self.plus(weeks=increment) 2239 else: 2240 newTime = self.clone() 2241 while newTime.weekday != argWeekday: 2242 newTime = newTime.plus(days=increment) 2243 return newTime
2244 2245 2246 #----------------------------------------------------------------------------------- 2247 # isLeapYear 2248 #-----------------------------------------------------------------------------------
2249 - def isLeapYear(self):
2250 """ 2251 Return a boolean indicating whether the year is or is not a leap year. 2252 2253 @return: True if a <year> is a leap year; otherwise return False. 2254 @rtype: boolean 2255 """ 2256 return isLeapYear(self.year)
2257 2258 2259 #----------------------------------------------------------------------------------- 2260 # subtract 2261 #-----------------------------------------------------------------------------------
2262 - def subtract(self, **kwargs):
2263 """ 2264 Subtract some amounts of time from the current time. Syntactic sugar 2265 for cases in which you don't want to "add" negative amounts of time. 2266 2267 @rtype: Time 2268 @return: a new Time object in which the time has been moved by the specified amounts. 2269 2270 Coding Example:: 2271 t1 = Time() 2272 t2 = t1.subtract(weeks=2,days=3,hours=4,minutes=99, seconds=1) 2273 """ 2274 for key,value in kwargs.items(): 2275 kwargs[key] = value * -1 2276 2277 return self.add(**kwargs)
2278 2279 # minus() method is alias for subtract() method 2280 minus = subtract
2281 #-------------------------------------------------------------------------------- 2282 # end of definition for Time class 2283 #-------------------------------------------------------------------------------- 2284 2285 2286 #################################################################################### 2287 #################################################################################### 2288 # 2289 # some useful functions 2290 # 2291 #################################################################################### 2292 #################################################################################### 2293 2294 #----------------------------------------------------------------------------- 2295 # argsToString 2296 #-----------------------------------------------------------------------------
2297 -def argsToString(*args):
2298 """ 2299 A utility routine for showing arguments in error messages. 2300 Useful for debugging. 2301 2302 >>> from pyfdate import * 2303 >>> s = argsToString("test",2,Time()) 2304 >>> print s 2305 arg 1: "test" <type 'str'> 2306 arg 2: 2 <type 'int'> 2307 arg 3: 2008-01-01 14:40:18 <type 'instance'> 2308 2309 @rtype: string 2310 """ 2311 s = "" 2312 for index, arg in enumerate(args): 2313 argnum = index + 1 2314 if type(arg) == type("aaa"): arg = '"%s"' % arg 2315 2316 s += ("arg " + str(argnum).rjust(5) 2317 + ': ' 2318 + str(arg) 2319 + ' ' 2320 + str(type(arg)) 2321 + '\n' 2322 ) 2323 return s
2324 2325 #----------------------------------------------------------------------------- 2326 # kwargsToString 2327 #-----------------------------------------------------------------------------
2328 -def kwargsToString(**kwargs):
2329 """ 2330 A utility routine for showing keyword arguments in error messages. 2331 Useful for debugging. 2332 2333 >>> from pyfdate import * 2334 >>> s = kwargsToString(first="test", second=2, third=Time()) 2335 >>> print s 2336 first : "test" <type 'str'> 2337 second : 2 <type 'int'> 2338 third : 2008-01-01 14:36:38 <type 'instance'> 2339 2340 @rtype: string 2341 """ 2342 s = "" 2343 keys = kwargs.keys() 2344 keys.sort() 2345 2346 for key in keys: 2347 value = kwargs[key] 2348 if type(value) == type("aaa"): value = '"%s"' % value 2349 s += (key.ljust(10) 2350 + ': ' 2351 + str(value) 2352 + ' ' 2353 + str(type(value)) 2354 + '\n') 2355 return s
2356 2357 2358 #----------------------------------------------------------------------------------- 2359 # NumericMonthToCalendarMonth 2360 #-----------------------------------------------------------------------------------
2361 -def CalendarMonthToNumericMonth(year, month):
2362 """ 2363 Convert a calendar month (year,month) 2364 to a numeric representation: 2365 2366 >>> CalendarMonthToNumericMonth(2007,4) 2367 24075 2368 2369 @rtype: int 2370 """ 2371 elapsedYears = year -1 2372 elapsedMonths = month -1 2373 return (elapsedYears * 12) + elapsedMonths
2374 2375 #----------------------------------------------------------------------------------- 2376 # NumericMonthToCalendarMonth 2377 #-----------------------------------------------------------------------------------
2378 -def NumericMonthToCalendarMonth(months):
2379 """ 2380 Convert a numeric representation of a month 2381 to a calendar month (year, month). 2382 2383 >>> NumericMonthToCalendarMonth(24075) 2384 (2007, 4) 2385 2386 @rtype: tuple 2387 """ 2388 elapsedYears, elapsedMonths = divmod(months, 12) 2389 year = elapsedYears + 1 2390 month = elapsedMonths + 1 2391 return year, month
2392 2393 2394 #----------------------------------------------------------------------------------- 2395 # isLeapYear 2396 #-----------------------------------------------------------------------------------
2397 -def isLeapYear(year):
2398 """ 2399 Return True if year is a leapyear; otherwise return False. 2400 2401 >>> isLeapYear(2004) 2402 True 2403 >>> isLeapYear(2000) 2404 True 2405 >>> isLeapYear(2005) 2406 False 2407 2408 @rtype: boolean 2409 @return: True if year is a leapyear; otherwise return False. 2410 """ 2411 try: 2412 # February 29 is valid only in a leap year 2413 d = datetime.datetime(year,2,29) 2414 return True 2415 except ValueError: 2416 return False
2417 2418 2419 #----------------------------------------------------------------------------------- 2420 # to24hour 2421 #-----------------------------------------------------------------------------------
2422 -def to24hour(hour, ampm):
2423 """ 2424 Convert an hour expressed as am/pm into one expressed in 24 hour time. 2425 2426 >>> to24hour(12,"am") 2427 0 2428 >>> to24hour(1,"am") 2429 1 2430 >>> to24hour(12,"PM") 2431 12 2432 >>> to24hour(1,"PM") 2433 13 2434 2435 @rtype: int 2436 @return: the number of of an hour in 24-hour (aka "military") time. 2437 2438 @type hour: int 2439 @arg hour: must be an integer (or a string that can be converted to an integer) 2440 in the range of 1 to 12 2441 2442 @type ampm: string 2443 @arg ampm: must be a string containing either "am" or "pm" (in upper or lower case) 2444 """ 2445 try: 2446 hour = int(hour) 2447 except: 2448 raise AssertionError('to24hour() function receives an ' 2449 + 'invalid value for hour argument: "' + str(hour) + '"') 2450 2451 ampm = ampm.lower() 2452 2453 assert hour < 13 2454 assert hour > 0 2455 assert ampm in ("am","pm") 2456 2457 if hour == 12 and ampm == 'am': return 0 2458 if hour == 12 and ampm == 'pm': return 12 2459 if ampm == 'pm': return hour + 12 2460 return hour
2461
2462 -def numsplit(s):
2463 """ 2464 split a string into its numeric parts and return 2465 a list containing the numeric parts converted to ints. 2466 2467 This function can be used to parse a string containing 2468 an ISO datetime. 2469 2470 >>> from pyfdate import * 2471 >>> numsplit("2007_10_09") 2472 [2007, 10, 9] 2473 >>> numsplit("2007-10-09T23:45:59") 2474 [2007, 10, 9, 23, 45, 59] 2475 >>> numsplit("2007/10/09 23.45.59") 2476 [2007, 10, 9, 23, 45, 59] 2477 """ 2478 s = list(s) 2479 for i in range(len(s)): 2480 if not s[i] in "0123456789": s[i] = " " 2481 return [int(x) for x in "".join(s).split()]
2482 2483 2484 #-------------------------------------------------------------------------- 2485 # test code 2486 #-------------------------------------------------------------------------- 2487 if __name__ == "__main__": 2488 print("pyfdate language is " + LANG) 2489 t = Time() 2490 print t.t 2491 print t.td 2492 print t.twd 2493 2494 print t.dt 2495 print t.dt2 2496 2497 print t.wdt 2498 print t.wdt2 2499 2500 print t.dt + " " + t.w 2501 print t.dt2 + " " + t.w 2502 print t.m + " " + t.y 2503 2504 for s in ( 2505 "2007_10_09" 2506 , "2007-10-09T23:45:59" 2507 , "2007/10/09 23.45.59" 2508 , "23:45:59" 2509 ): 2510 print(s.ljust(30)+ " --> " + str(numsplit(s))) 2511 2512 print "It is now:", t 2513