The TjTime class is based on the original Ruby class Time but provides lots of additional functionality.
The number of days per month. Leap years are taken care of separately.
Check if zone is a valid time zone.
# File lib/TjTime.rb, line 169 169: def TjTime.checkTimeZone(zone) 170: return true if zone == 'UTC' 171: 172: # Valid time zones must be of the form 'Region/City' 173: return false unless zone.include?('/') 174: 175: # Save curent value of TZ 176: tz = ENV['TZ'] 177: ENV['TZ'] = zone 178: newZone = Time.new.zone 179: # If the time zone is valid, the OS can convert a zone like 180: # 'America/Denver' into 'MST'. Unknown time zones are either not 181: # converted or cause a fallback to UTC. 182: # Since glibc 2.10 Time.new.zone only return the region for illegal 183: # zones instead of the full zone string like it does on earlier 184: # versions. 185: region = zone[0..zone.index('/') - 1] 186: res = (newZone != zone && newZone != region && newZone != 'UTC') 187: # Restore TZ if it was set earlier. 188: if tz 189: ENV['TZ'] = tz 190: else 191: ENV.delete('TZ') 192: end 193: res 194: end
Creates a time based on given values, interpreted as UTC. See Time.gm() for details.
# File lib/TjTime.rb, line 53 53: def TjTime.gm(*args) 54: TjTime.new(Time.gm(*args)) 55: end
Creates a time based on given values, interpreted as local time. The result is stored as UTC time, though. See Time.local() for details.
# File lib/TjTime.rb, line 59 59: def TjTime.local(*args) 60: TjTime.new(Time.local(*args).gmtime) 61: end
The constructor is overloaded and accepts 3 kinds of arguments. If t is a Time object this is just copied to the @time variable. If it’s a string, it is parsed as a date. Or else it is interpreted as seconds after Epoch.
# File lib/TjTime.rb, line 36 36: def initialize(t) 37: if t.is_a?(Time) 38: @time = t 39: elsif t.is_a?(String) 40: @time = TjTime.parse(t).time 41: else 42: @time = Time.at(t) 43: end 44: end
Returns the current UTC time as Time object.
# File lib/TjTime.rb, line 47 47: def TjTime.now 48: TjTime.new(Time.now.gmtime) 49: end
# File lib/TjTime.rb, line 63 63: def TjTime.parse(t) 64: year, month, day, time, zone = t.split('-', 5) 65: 66: # Check the year 67: if year 68: year = year.to_i 69: if year < 1970 || year > 2035 70: raise TjException.new, "Year #{year} out of range (1970 - 2035)" 71: end 72: else 73: raise TjException.new, "Year not specified" 74: end 75: 76: # Check the month 77: if month 78: month = month.to_i 79: if month < 1 || month > 12 80: raise TjException.new, "Month #{month} out of range (1 - 12)" 81: end 82: else 83: raise TjException.new, "Month not specified" 84: end 85: 86: # Check the day 87: if day 88: day = day.to_i 89: maxDay = [ 0, 31, Date.gregorian_leap?(year) ? 29 : 28, 31, 30, 31, 90: 30, 31, 31, 30, 31, 30, 31 ] 91: if month < 1 || month > maxDay[month] 92: raise TjException.new, "Day #{day} out of range (1 - #{maxDay[month]})" 93: end 94: else 95: raise TjException.new, "Day not specified" 96: end 97: 98: # The time is optional. Will be expanded to 00:00:00. 99: if time 100: hour, minute, second = time.split(':') 101: 102: # Check hour 103: if hour 104: hour = hour.to_i 105: if hour < 0 || hour > 23 106: raise TjException.new, "Hour #{hour} out of range (0 - 23)" 107: end 108: else 109: raise TjException.new, "Hour not specified" 110: end 111: 112: if minute 113: minute = minute.to_i 114: if minute < 0 || minute > 59 115: raise TjException.new, "Minute #{minute} out of range (0 - 59)" 116: end 117: else 118: raise TjException.new, "Minute not specified" 119: end 120: 121: # Check sencond. This value is optional and defaults to 0. 122: if second 123: second = second.to_i 124: if second < 0 || second > 59 125: raise TjException.new, "Second #{second} out of range (0 - 59)" 126: end 127: else 128: second = 0 129: end 130: else 131: hour = minute = second = 0 132: end 133: 134: # The zone is optional and defaults to the current time zone. 135: if zone 136: if zone[0] != -- && zone[0] != ++ 137: raise TjException.new, "Time zone adjustment must be prefixed by " + 138: "+ or -, not #{zone[0]}" 139: end 140: if zone.length != 5 141: raise TjException.new, "Time zone adjustment must use (+/-)HHMM format" 142: end 143: 144: date = Time.utc(year, month, day, hour, minute, second) 145: sign = zone[0] == -- ? 1 : 1 146: tzHour = zone[1..2].to_i 147: if tzHour < 0 || tzHour > 12 148: raise TjException.new, "Time zone adjustment hour out of range " + 149: "(0 - 12) but is #{tzHour}" 150: end 151: tzMinute = zone[3..4].to_i 152: if tzMinute < 0 || tzMinute > 59 153: raise TjException.new, "Time zone adjustment minute out of range " + 154: "(0 - 59) but is #{tzMinute}" 155: end 156: date += sign * (tzHour * 3600 + tzMinute * 60) 157: else 158: date = Time.mktime(year, month, day, hour, minute, second) 159: end 160: 161: #puts "--> #{t}" 162: #puts(">>> #{year}-#{month}-#{day}-#{hour}:#{minute}:#{second}" + 163: # "#{zone ? "-#{tzHour}:#{tzMinute}" : ""}") 164: #puts "=== #{date}" 165: TjTime.new(date) 166: end
Convert the time to seconds since Epoch and return the module of val.
# File lib/TjTime.rb, line 224 224: def %(val) 225: @time.to_i % val 226: end
Add secs number of seconds to the time.
# File lib/TjTime.rb, line 209 209: def +(secs) 210: TjTime.new(@time + secs) 211: end
Substract arg number of seconds or return the number of seconds between arg and this time.
# File lib/TjTime.rb, line 215 215: def -(arg) 216: if arg.is_a?(TjTime) 217: @time - arg.time 218: else 219: TjTime.new(@time - arg) 220: end 221: end
Return true if time is smaller than t.
# File lib/TjTime.rb, line 229 229: def <(t) 230: @time < t.time 231: end
Return true if time is smaller or equal than t.
# File lib/TjTime.rb, line 234 234: def <=(t) 235: @time <= t.time 236: end
Coparison operator for time with another time t.
# File lib/TjTime.rb, line 255 255: def <=>(t) 256: @time <=> t.time 257: end
Return true if time and t are identical.
# File lib/TjTime.rb, line 249 249: def ==(t) 250: return false if t.nil? 251: @time == t.time 252: end
Return true if time is larger than t.
# File lib/TjTime.rb, line 239 239: def >(t) 240: @time > t.time 241: end
Return true if time is larger or equal than t.
# File lib/TjTime.rb, line 244 244: def >=(t) 245: @time >= t.time 246: end
Align the date to a time grid. The grid distance is determined by clock.
# File lib/TjTime.rb, line 197 197: def align(clock) 198: TjTime.new((@time.to_i / clock) * clock) 199: end
Normalize time to the beginning of the current hour.
# File lib/TjTime.rb, line 270 270: def beginOfHour 271: t = @time.localtime.to_a 272: t[0, 2] = Array.new(2, 0) 273: t.slice!(6, 4) 274: t.reverse! 275: TjTime.new(Time.local(*t)) 276: end
Normalize time to the beginning of the current month.
# File lib/TjTime.rb, line 303 303: def beginOfMonth 304: t = @time.localtime.to_a 305: t[0, 3] = Array.new(3, 0) 306: t[3] = 1 307: t.slice!(6, 4) 308: t.reverse! 309: TjTime.new(Time.local(*t)) 310: end
Normalize time to the beginning of the current quarter.
# File lib/TjTime.rb, line 313 313: def beginOfQuarter 314: t = @time.localtime.to_a 315: t[0, 3] = Array.new(3, 0) 316: t[3] = 1 317: t[4] = ((t[4] - 1) % 3) + 1 318: t.slice!(6, 4) 319: t.reverse! 320: TjTime.new(Time.local(*t)) 321: end
Normalize time to the beginning of the current week. startMonday determines whether the week should start on Monday or Sunday.
# File lib/TjTime.rb, line 289 289: def beginOfWeek(startMonday) 290: t = @time.to_a 291: # Set time to noon, 12:00:00 292: t[0, 3] = [ 0, 0, 12 ] 293: weekday = t[6] 294: t.slice!(6, 4) 295: t.reverse! 296: # Substract the number of days determined by the weekday t[6] and set time 297: # to midnight of that day. 298: (TjTime.new(Time.local(*t)) - 299: (weekday - (startMonday ? 1 : 0)) * 60 * 60 * 24).midnight 300: end
Normalize time to the beginning of the current year.
# File lib/TjTime.rb, line 324 324: def beginOfYear 325: t = @time.localtime.to_a 326: t[0, 3] = Array.new(3, 0) 327: t[3, 2] = Array.new(2, 1) 328: t.slice!(6, 4) 329: t.reverse! 330: TjTime.new(Time.local(*t)) 331: end
Return the number of days between this time and date. The result is always rounded up.
# File lib/TjTime.rb, line 415 415: def daysTo(date) 416: countIntervals(date, :sameTimeNextDay) 417: end
Return a new time that is hours later than time.
# File lib/TjTime.rb, line 334 334: def hoursLater(hours) 335: TjTime.new(@time + hours * 3600) 336: end
Return the number of hours between this time and date. The result is always rounded up.
# File lib/TjTime.rb, line 408 408: def hoursTo(date) 409: t1, t2 = order(date) 410: ((t2 - t1) / 3600).ceil 411: end
Pass any unknown function directoy to the @time variable.
# File lib/TjTime.rb, line 504 504: def method_missing(func, *args) 505: @time.method(func).call(*args) 506: end
Normalize time to the beginning of the current day.
# File lib/TjTime.rb, line 279 279: def midnight 280: t = @time.localtime.to_a 281: t[0, 3] = Array.new(3, 0) 282: t.slice!(6, 4) 283: t.reverse! 284: TjTime.new(Time.local(*t)) 285: end
Return the abbreviated month name and the full year. E. g. ‘Feb 1972’.
# File lib/TjTime.rb, line 481 481: def monthAndYear 482: @time.strftime('%b %Y') 483: end
Return the number of months between this time and date. The result is always rounded up.
# File lib/TjTime.rb, line 427 427: def monthsTo(date) 428: countIntervals(date, :sameTimeNextMonth) 429: end
Return the start of the next dow day of week after date. dow must be 0 for Sundays, 1 for Mondays and 6 for Saturdays. If date is a Tuesday and dow is 5 (Friday) the date of next Friday 0:00 will be returned. If date is a Tuesday and dow is 2 (Tuesday) the date of the next Tuesday will be returned.
# File lib/TjTime.rb, line 495 495: def nextDayOfWeek(dow) 496: raise "Day of week must be 0 - 6." unless dow >= 0 && dow <= 6 497: d = midnight.sameTimeNextDay 498: currentDoW = d.strftime('%w').to_i 499: 1.upto((dow + 7 - currentDoW) % 7) { |i| d = d.sameTimeNextDay } 500: d 501: end
Return the number of the quarter prefixed by a ‘Q’.
# File lib/TjTime.rb, line 470 470: def quarterName 471: "Q#{(@time.mon / 3) + 1}" 472: end
Return the number of quarters between this time and date. The result is always rounded up.
# File lib/TjTime.rb, line 433 433: def quartersTo(date) 434: countIntervals(date, :sameTimeNextQuarter) 435: end
Return a new time that is 1 day later than time but at the same time of day.
# File lib/TjTime.rb, line 345 345: def sameTimeNextDay 346: delta = [ 0, 1, 1 ] 347: localT1 = @time.localtime.to_a 348: delta.each do |d| 349: t = @time + (24 + d) * 60 * 60 350: localT2 = t.localtime.to_a 351: return TjTime.new(t) if localT1[0, 3] == localT2[0, 3] 352: end 353: raise "Algorithm is broken for #{@time}" 354: end
Return a new time that is 1 hour later than time.
# File lib/TjTime.rb, line 339 339: def sameTimeNextHour 340: hoursLater(1) 341: end
Return a new time that is 1 month later than time but at the same time of day.
# File lib/TjTime.rb, line 371 371: def sameTimeNextMonth 372: sec, min, hour, day, month, year = @time.localtime.to_a 373: monMax = month == 2 && leapYear?(year) ? 29 : MON_MAX[month] 374: month += 1 375: if month > 12 376: month = 1 377: year += 1 378: end 379: day = monMax if day >= monMax 380: TjTime.new(Time.mktime(year, month, day, hour, min, sec, 0)) 381: end
Return a new time that is 1 quarter later than time but at the same time of day.
# File lib/TjTime.rb, line 385 385: def sameTimeNextQuarter 386: t = @time.localtime.to_a 387: if (t[4] += 3) > 12 388: t[4] -= 12 389: t[5] += 1 390: end 391: t.slice!(6, 4) 392: t.reverse! 393: TjTime.new(Time.local(*t)) 394: end
Return a new time that is 1 week later than time but at the same time of day.
# File lib/TjTime.rb, line 358 358: def sameTimeNextWeek 359: delta = [ 0, 1, 1 ] 360: localT1 = @time.localtime.to_a 361: delta.each do |d| 362: t = @time + (7 * 24 + d) * 60 * 60 363: localT2 = t.localtime.to_a 364: return TjTime.new(t) if localT1[0, 3] == localT2[0, 3] 365: end 366: raise "Algorithm is broken for #{@time}" 367: end
Return a new time that is 1 year later than time but at the same time of day.
# File lib/TjTime.rb, line 398 398: def sameTimeNextYear 399: t = @time.localtime.to_a 400: t[5] += 1 401: t.slice!(6, 4) 402: t.reverse! 403: TjTime.new(Time.local(*t)) 404: end
Returns the total number of seconds of the day. The time is assumed to be in the time zone specified by tz.
# File lib/TjTime.rb, line 203 203: def secondsOfDay(tz = nil) 204: # TODO: Add timezone support 205: (@time.to_i + @time.gmt_offset) % (60 * 60 * 24) 206: end
Return the abbreviated month name.
# File lib/TjTime.rb, line 465 465: def shortMonthName 466: @time.strftime('%b') 467: end
Return the seconds since Epoch.
# File lib/TjTime.rb, line 455 455: def to_i 456: @time.to_i 457: end
This function is just a wrapper around Time.strftime(). In case @time is nil, it returns ‘unkown’.
# File lib/TjTime.rb, line 445 445: def to_s(format = nil) 446: return 'unknown' if @time.nil? 447: if format.nil? 448: format = '%Y-%m-%d-%H:%M' + (@time.sec == 0 ? '' : ':%S') + '-%z' 449: end 450: # Always report values in local timezone 451: @time.dup.localtime.strftime(format) 452: end
Iterator that executes the block until time has reached endDate increasing time by step on each iteration.
# File lib/TjTime.rb, line 261 261: def upto(endDate, step = 1) 262: t = @time 263: while t < endDate.time 264: yield(TjTime.new(t)) 265: t += step 266: end 267: end
Return the week number. weekStartsMonday specifies wheter the counting should be for weeks starting Mondays or Sundays.
# File lib/TjTime.rb, line 476 476: def week(weekStartsMonday) 477: @time.strftime(weekStartsMonday ? '%W' : '%U') 478: end
Return the abbreviated weekday and the full date. E. g. ‘Sat 2007-11-03’.
# File lib/TjTime.rb, line 486 486: def weekdayAndDate 487: @time.strftime('%A %Y-%m-%d') 488: end
# File lib/TjTime.rb, line 521 521: def countIntervals(date, stepFunc) 522: i = 0 523: t1, t2 = order(date) 524: while t1 < t2 525: t1 = t1.send(stepFunc) 526: i += 1 527: end 528: i 529: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.