summary refs log blame commit diff stats
path: root/lib/pure/times.nim
blob: 793b55eadb3a827db3e7cc74fb6d19aa6f9c4471 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                                     
                                         






                                                                 
                                                      











                                                                          












                                                                  




































                                       
 
    
                                                                        












                                                                            
                                                                      















                                                                             
                                                              
                               
                                                         









                                                                         







                                                                 


                                                      
 
                               












































                                                                                
                                    
















                                                             
                                       



















                                                                          







                                                            
                                         


                                                   

                                 
                                                 
                
                                         
 











                                                                  


                                                       


                                               









































                                                                            


                                  

                                                          





                                                                
       
#
#
#            Nimrod's Runtime Library
#        (c) Copyright 2009 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#


## This module contains routines and types for dealing with time.
## This module is available for the ECMAScript target.

{.push debugger:off .} # the user does not want to trace a part
                       # of the standard library!

import
  strutils

type
  TMonth* = enum ## represents a month
    mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
  TWeekDay* = enum ## represents a weekday
    dMon, dTue, dWed, dThu, dFri, dSat, dSun
    
when defined(posix): 
  type
    TTime* = abstract int ## abstract type that represents a time
elif defined(windows):
  when defined(vcc):
    # newest version of Visual C++ defines time_t to be of 64 bits
    type TTime* = abstract int64
  else:
    type TTime* = abstract int32
elif defined(ECMAScript):
  type
    TTime* {.final.} = object
      getDay: proc (): int
      getFullYear: proc (): int
      getHours: proc (): int
      getMilliseconds: proc (): int
      getMinutes: proc (): int
      getMonth: proc (): int
      getSeconds: proc (): int
      getTime: proc (): int
      getTimezoneOffset: proc (): int
      getUTCDate: proc (): int
      getUTCFullYear: proc (): int
      getUTCHours: proc (): int
      getUTCMilliseconds: proc (): int
      getUTCMinutes: proc (): int
      getUTCMonth: proc (): int
      getUTCSeconds: proc (): int
      getYear: proc (): int
      parse: proc (s: cstring): TTime
      setDate: proc (x: int)
      setFullYear: proc (x: int)
      setHours: proc (x: int)
      setMilliseconds: proc (x: int)
      setMinutes: proc (x: int)
      setMonth: proc (x: int)
      setSeconds: proc (x: int)
      setTime: proc (x: int)
      setUTCDate: proc (x: int)
      setUTCFullYear: proc (x: int)
      setUTCHours: proc (x: int)
      setUTCMilliseconds: proc (x: int)
      setUTCMinutes: proc (x: int)
      setUTCMonth: proc (x: int)
      setUTCSeconds: proc (x: int)
      setYear: proc (x: int)
      toGMTString: proc (): cstring
      toLocaleString: proc (): cstring
      UTC: proc (): int

type
  TTimeInfo* = object of TObject ## represents a time in different parts
    second*: range[0..61]     ## The number of seconds after the minute,
                              ## normally in the range 0 to 59, but can
                              ## be up to 61 to allow for leap seconds.
    minute*: range[0..59]     ## The number of minutes after the hour,
                              ## in the range 0 to 59.
    hour*: range[0..23]       ## The number of hours past midnight,
                              ## in the range 0 to 23.
    monthday*: range[1..31]   ## The day of the month, in the range 1 to 31.
    month*: TMonth            ## The current month.
    year*: int                ## The current year.
    weekday*: TWeekDay        ## The current day of the week.
    yearday*: range[0..365]   ## The number of days since January 1,
                              ## in the range 0 to 365.
                              ## Always 0 if the target is ECMAScript.

proc getTime*(): TTime ## gets the current calendar time
proc getLocalTime*(t: TTime): TTimeInfo
  ## converts the calendar time `t` to broken-time representation,
  ## expressed relative to the user's specified time zone.
proc getGMTime*(t: TTime): TTimeInfo
  ## converts the calendar time `t` to broken-down time representation,
  ## expressed in Coordinated Universal Time (UTC).

proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
  ## converts a broken-down time structure, expressed as local time, to
  ## calendar time representation. The function ignores the specified
  ## contents of the structure members `weekday` and `yearday` and recomputes
  ## them from the other information in the broken-down time structure.

proc `$` *(timeInfo: TTimeInfo): string
  ## converts a `TTimeInfo` object to a string representation.
proc `$` *(time: TTime): string
  ## converts a calendar time to a string representation.

proc getDateStr*(): string
  ## gets the current date as a string of the format
  ## ``YYYY-MM-DD``.
proc getClockStr*(): string
  ## gets the current clock time as a string of the format ``HH:MM:SS``.

proc `-` *(a, b: TTime): int64
  ## computes the difference of two calendar times. Result is in seconds.

proc `<` * (a, b: TTime): bool = 
  ## returns true iff ``a < b``, that is iff a happened before b.
  result = a - b < 0
  
proc `<=` * (a, b: TTime): bool = 
  ## returns true iff ``a <= b``.
  result = a - b <= 0

proc getStartMilsecs*(): int
  ## get the miliseconds from the start of the program


when not defined(ECMAScript):  
  # C wrapper:
  type
    structTM {.importc: "struct tm", final.} = object
      second {.importc: "tm_sec".},
        minute {.importc: "tm_min".},
        hour {.importc: "tm_hour".},
        monthday {.importc: "tm_mday".},
        month {.importc: "tm_mon".},
        year {.importc: "tm_year".},
        weekday {.importc: "tm_wday".},
        yearday {.importc: "tm_yday".},
        isdst {.importc: "tm_isdst".}: cint
  
    PTimeInfo = ptr structTM
    PTime = ptr TTime
  
    TClock {.importc: "clock_t".} = range[low(int)..high(int)]
  
  proc localtime(timer: PTime): PTimeInfo {.
    importc: "localtime", header: "<time.h>".}
  proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
  proc timec(timer: PTime): TTime      {.importc: "time", header: "<time.h>".}
  proc mktime(t: structTM): TTime      {.importc: "mktime", header: "<time.h>".}
  proc asctime(tblock: structTM): CString {.
    importc: "asctime", header: "<time.h>".}
  proc ctime(time: PTime): CString     {.importc: "ctime", header: "<time.h>".}
  #  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
  #    importc: "strftime", header: "<time.h>".}
  proc clock(): TClock {.importc: "clock", header: "<time.h>".}
  proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
  
  var
    clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
  
  
  # our own procs on top of that:
  proc tmToTimeInfo(tm: structTM): TTimeInfo =
    const
      weekDays: array [0..6, TWeekDay] = [
        dSun, dMon, dTue, dWed, dThu, dFri, dSat]
    result.second = int(tm.second)
    result.minute = int(tm.minute)
    result.hour = int(tm.hour)
    result.monthday = int(tm.monthday)
    result.month = TMonth(tm.month)
    result.year = tm.year + 1900'i32
    result.weekday = weekDays[int(tm.weekDay)]
    result.yearday = int(tm.yearday)
  
  proc timeInfoToTM(t: TTimeInfo): structTM =
    const
      weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
    result.second = t.second
    result.minute = t.minute
    result.hour = t.hour
    result.monthday = t.monthday
    result.month = ord(t.month)
    result.year = t.year - 1900
    result.weekday = weekDays[t.weekDay]
    result.yearday = t.yearday
    result.isdst = -1
  
  proc `-` (a, b: TTime): int64 =
    return toBiggestInt(difftime(a, b))
  
  proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
  proc getTime(): TTime = return timec(nil)
  proc getLocalTime(t: TTime): TTimeInfo =
    var a = t
    result = tmToTimeInfo(localtime(addr(a))^)
    # copying is needed anyway to provide reentrancity; thus
    # the convertion is not expensive
  
  proc getGMTime(t: TTime): TTimeInfo =
    var a = t
    result = tmToTimeInfo(gmtime(addr(a))^)
    # copying is needed anyway to provide reentrancity; thus
    # the convertion is not expensive
  
  proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
    var cTimeInfo = timeInfo # for C++ we have to make a copy,
    # because the header of mktime is broken in my version of libc
    return mktime(timeInfoToTM(cTimeInfo))
    
  proc toStringTillNL(p: cstring): string = 
    result = ""
    var i = 0
    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13': 
      add(result, p[i])
      inc(i)
    return result
    
  proc `$`(timeInfo: TTimeInfo): string =
    # BUGFIX: asctime returns a newline at the end!
    var p = asctime(timeInfoToTM(timeInfo))
    result = toStringTillNL(p)
  
  proc `$`(time: TTime): string =
    # BUGFIX: ctime returns a newline at the end!
    var a = time
    return toStringTillNL(ctime(addr(a)))

  const
    epochDiff = 116444736000000000'i64
    rateDiff = 10000000'i64 # 100 nsecs

  proc unixTimeToWinTime*(t: TTime): int64 = 
    ## converts a UNIX `TTime` (``time_t``) to a Windows file time
    result = int64(t) * rateDiff + epochDiff
    
  proc winTimeToUnixTime*(t: int64): TTime = 
    ## converts a Windows time to a UNIX `TTime` (``time_t``)
    result = TTime((t - epochDiff) div rateDiff)

else:
  proc getTime(): TTime {.importc: "new Date", nodecl.}

  const
    weekDays: array [0..6, TWeekDay] = [
      dSun, dMon, dTue, dWed, dThu, dFri, dSat]
  
  proc getLocalTime(t: TTime): TTimeInfo =
    result.second = t.getSeconds()
    result.minute = t.getMinutes()
    result.hour = t.getHours()
    result.monthday = t.getDate()
    result.month = TMonth(t.getMonth())
    result.year = t.getFullYear()
    result.weekday = weekDays[t.getDay()]
    result.yearday = 0

  proc getGMTime(t: TTime): TTimeInfo =
    result.second = t.getUTCSeconds()
    result.minute = t.getUTCMinutes()
    result.hour = t.getUTCHours()
    result.monthday = t.getUTCDate()
    result.month = TMonth(t.getUTCMonth())
    result.year = t.getUTCFullYear()
    result.weekday = weekDays[t.getDay()]
    result.yearday = 0
  
  proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime =
    result = getTime()
    result.setSeconds(timeInfo.second)
    result.setMinutes(timeInfo.minute)
    result.setHours(timeInfo.hour)
    result.setMonth(ord(timeInfo.month))
    result.setFullYear(timeInfo.year)
    result.setDate(timeInfo.monthday)
  
  proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo))
  proc `$`(time: TTime): string = $time.toLocaleString()
    
  proc `-` (a, b: TTime): int64 = 
    return a.getTime() - b.getTime()
  
  var
    startMilsecs = getTime()
  
  proc getStartMilsecs(): int =
    ## get the miliseconds from the start of the program
    return int(getTime() - startMilsecs)

proc getDateStr(): string =
  var ti = getLocalTime(getTime())
  result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
    '-' & intToStr(ti.monthDay, 2)

proc getClockStr(): string =
  var ti = getLocalTime(getTime())
  result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
    ':' & intToStr(ti.second, 2)

{.pop.}