Class: TaskJuggler::TjTime

Inherits:
Object show all
Defined in:
lib/taskjuggler/TjTime.rb

Overview

The TjTime class extends the original Ruby class Time with lots of TaskJuggler specific additional functionality. This is mostly for handling time zones.

Constant Summary collapse

MON_MAX =

The number of days per month. Leap years are taken care of separately.

[ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
@@tz =

Initialize @@tz with the current time zone if it is set.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(t = nil) ⇒ TjTime

call-seq:

TjTime() -> TjTime (now)
TjTime(tjtime) -> TjTime
TjTime(time, timezone) -> TjTime
TjTime(str) -> TjTime
TjTime(secs) -> TjTime

The constructor is overloaded and accepts 4 kinds of arguments. If t is a Time object it’s assumed to be in local time. If it’s a string, it is parsed as a date. Or else it is interpreted as seconds after Epoch.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/taskjuggler/TjTime.rb', line 42

def initialize(t = nil)
  case t
  when nil
    @time = Time.now
  when Time
    @time = t
  when TjTime
    @time = t.time
  when String
    parse(t)
  when Array
    @time = Time.mktime(*t)
  else
    @time = Time.at(t)
  end
end

Instance Attribute Details

#timeObject (readonly)

Returns the value of attribute time.



24
25
26
# File 'lib/taskjuggler/TjTime.rb', line 24

def time
  @time
end

Class Method Details

.checkTimeZone(zone) ⇒ Object

Check if zone is a valid time zone.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/taskjuggler/TjTime.rb', line 60

def TjTime.checkTimeZone(zone)
  return true if zone == 'UTC'

  # Valid time zones must be of the form 'Region/City'
  return false unless zone.include?('/')

  # Save curent value of TZ
  tz = ENV['TZ']
  ENV['TZ'] = zone
  newZone = Time.new.zone
  # If the time zone is valid, the OS can convert a zone like
  # 'America/Denver' into 'MST'. Unknown time zones are either not
  # converted or cause a fallback to UTC.
  # Since glibc 2.10 Time.new.zone only return the region for illegal
  # zones instead of the full zone string like it does on earlier
  # versions.
  region = zone[0..zone.index('/') - 1]
  res = (newZone != zone && newZone != region && newZone != 'UTC')
  # Restore TZ if it was set earlier.
  if tz
    ENV['TZ'] = tz
  else
    ENV.delete('TZ')
  end
  res
end

.setTimeZone(zone) ⇒ Object

Set a new active time zone. zone must be a valid String known to the underlying operating system.



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/taskjuggler/TjTime.rb', line 89

def TjTime.setTimeZone(zone)
  unless zone && TjTime.checkTimeZone(zone)
    raise "Illegal time zone #{zone}"
  end

  oldTimeZone = @@tz

  @@tz = zone
  ENV['TZ'] = zone

  oldTimeZone
end

.timeZoneObject

Return the name of the currently active time zone.



103
104
105
# File 'lib/taskjuggler/TjTime.rb', line 103

def TjTime.timeZone
  @@tz
end

Instance Method Details

#%(val) ⇒ Object

Convert the time to seconds since Epoch and return the module of val.



140
141
142
# File 'lib/taskjuggler/TjTime.rb', line 140

def %(val)
  @time.to_i % val
end

#+(secs) ⇒ Object

Add secs number of seconds to the time.



125
126
127
# File 'lib/taskjuggler/TjTime.rb', line 125

def +(secs)
  TjTime.new(@time.to_i + secs)
end

#-(arg) ⇒ Object

Substract arg number of seconds or return the number of seconds between arg and this time.



131
132
133
134
135
136
137
# File 'lib/taskjuggler/TjTime.rb', line 131

def -(arg)
  if arg.is_a?(TjTime)
    @time - arg.time
  else
    TjTime.new(@time.to_i - arg)
  end
end

#<(t) ⇒ Object

Return true if time is smaller than t.



145
146
147
148
# File 'lib/taskjuggler/TjTime.rb', line 145

def <(t)
  return false unless t
  @time < t.time
end

#<=(t) ⇒ Object

Return true if time is smaller or equal than t.



151
152
153
154
# File 'lib/taskjuggler/TjTime.rb', line 151

def <=(t)
  return false unless t
  @time <= t.time
end

#<=>(t) ⇒ Object

Coparison operator for time with another time t.



175
176
177
178
# File 'lib/taskjuggler/TjTime.rb', line 175

def <=>(t)
  return -1 unless t
  @time <=> t.time
end

#==(t) ⇒ Object

Return true if time and t are identical.



169
170
171
172
# File 'lib/taskjuggler/TjTime.rb', line 169

def ==(t)
  return false unless t
  @time == t.time
end

#>(t) ⇒ Object

Return true if time is larger than t.



157
158
159
160
# File 'lib/taskjuggler/TjTime.rb', line 157

def >(t)
  return true unless t
  @time > t.time
end

#>=(t) ⇒ Object

Return true if time is larger or equal than t.



163
164
165
166
# File 'lib/taskjuggler/TjTime.rb', line 163

def >=(t)
  return true unless t
  @time >= t.time
end

#align(clock) ⇒ Object

Align the date to a time grid. The grid distance is determined by clock.



108
109
110
# File 'lib/taskjuggler/TjTime.rb', line 108

def align(clock)
  TjTime.new((localtime.to_i / clock) * clock)
end

#beginOfHourObject

Normalize time to the beginning of the current hour.



191
192
193
194
195
# File 'lib/taskjuggler/TjTime.rb', line 191

def beginOfHour
  sec, min, hour, day, month, year = localtime.to_a
  sec = min = 0
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#beginOfMonthObject

Normalize time to the beginning of the current month.



220
221
222
223
224
225
# File 'lib/taskjuggler/TjTime.rb', line 220

def beginOfMonth
  sec, min, hour, day, month, year = localtime.to_a
  sec = min = hour = 0
  day = 1
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#beginOfQuarterObject

Normalize time to the beginning of the current quarter.



228
229
230
231
232
233
234
# File 'lib/taskjuggler/TjTime.rb', line 228

def beginOfQuarter
  sec, min, hour, day, month, year = localtime.to_a
  sec = min = hour = 0
  day = 1
  month = ((month - 1) % 3 ) + 1
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#beginOfWeek(startMonday) ⇒ Object

Normalize time to the beginning of the current week. startMonday determines whether the week should start on Monday or Sunday.



206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/taskjuggler/TjTime.rb', line 206

def beginOfWeek(startMonday)
  t = localtime.to_a
  # Set time to noon, 12:00:00
  t[0, 3] = [ 0, 0, 12 ]
  weekday = t[6]
  t.slice!(6, 4)
  t.reverse!
  # Substract the number of days determined by the weekday t[6] and set time
  # to midnight of that day.
  (TjTime.new(Time.local(*t)) -
   (weekday - (startMonday ? 1 : 0)) * 60 * 60 * 24).midnight
end

#beginOfYearObject

Normalize time to the beginning of the current year.



237
238
239
240
241
242
# File 'lib/taskjuggler/TjTime.rb', line 237

def beginOfYear
  sec, min, hour, day, month, year = localtime.to_a
  sec = min = hour = 0
  day = month = 1
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#dayObject

Return the day of the month (1..n).



404
405
406
# File 'lib/taskjuggler/TjTime.rb', line 404

def day
  localtime.day
end

#daysTo(date) ⇒ Object

Return the number of days between this time and date. The result is always rounded up.



336
337
338
# File 'lib/taskjuggler/TjTime.rb', line 336

def daysTo(date)
  countIntervals(date, :sameTimeNextDay)
end

#hourObject

Return the hours of the day (0..23)



399
400
401
# File 'lib/taskjuggler/TjTime.rb', line 399

def hour
  localtime.hour
end

#hoursLater(hours) ⇒ Object

Return a new time that is hours later than time.



245
246
247
# File 'lib/taskjuggler/TjTime.rb', line 245

def hoursLater(hours)
  TjTime.new(@time + hours * 3600)
end

#hoursTo(date) ⇒ Object

Return the number of hours between this time and date. The result is always rounded up.



329
330
331
332
# File 'lib/taskjuggler/TjTime.rb', line 329

def hoursTo(date)
  t1, t2 = order(date)
  ((t2 - t1) / 3600).ceil
end

#midnightObject

Normalize time to the beginning of the current day.



198
199
200
201
202
# File 'lib/taskjuggler/TjTime.rb', line 198

def midnight
  sec, min, hour, day, month, year = localtime.to_a
  sec = min = hour = 0
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#monthObject Also known as: mon

Return the month of the year (1..12)



409
410
411
# File 'lib/taskjuggler/TjTime.rb', line 409

def month
  localtime.month
end

#monthsTo(date) ⇒ Object

Return the number of months between this time and date. The result is always rounded up.



348
349
350
# File 'lib/taskjuggler/TjTime.rb', line 348

def monthsTo(date)
  countIntervals(date, :sameTimeNextMonth)
end

#nextDayOfWeek(dow) ⇒ Object

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.



319
320
321
322
323
324
325
# File 'lib/taskjuggler/TjTime.rb', line 319

def nextDayOfWeek(dow)
  raise "Day of week must be 0 - 6." unless dow >= 0 && dow <= 6
  d = midnight.sameTimeNextDay
  currentDoW = d.strftime('%w').to_i
  1.upto((dow + 7 - currentDoW) % 7) { |i| d = d.sameTimeNextDay }
  d
end

#quartersTo(date) ⇒ Object

Return the number of quarters between this time and date. The result is always rounded up.



354
355
356
# File 'lib/taskjuggler/TjTime.rb', line 354

def quartersTo(date)
  countIntervals(date, :sameTimeNextQuarter)
end

#sameTimeNextDayObject

Return a new time that is 1 day later than time but at the same time of day.



256
257
258
259
260
261
262
263
264
265
266
# File 'lib/taskjuggler/TjTime.rb', line 256

def sameTimeNextDay
  sec, min, hour, day, month, year = localtime.to_a
  if (day += 1) > lastDayOfMonth(month, year)
    day = 1
    if (month += 1) > 12
      month = 1
      year += 1
    end
  end
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#sameTimeNextHourObject

Return a new time that is 1 hour later than time.



250
251
252
# File 'lib/taskjuggler/TjTime.rb', line 250

def sameTimeNextHour
  hoursLater(1)
end

#sameTimeNextMonthObject

Return a new time that is 1 month later than time but at the same time of day.



284
285
286
287
288
289
290
291
292
293
# File 'lib/taskjuggler/TjTime.rb', line 284

def sameTimeNextMonth
  sec, min, hour, day, month, year = localtime.to_a
  monMax = month == 2 && leapYear?(year) ? 29 : MON_MAX[month]
  if (month += 1) > 12
    month = 1
    year += 1
  end
  day = monMax if day >= lastDayOfMonth(month, year)
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#sameTimeNextQuarterObject

Return a new time that is 1 quarter later than time but at the same time of day.



297
298
299
300
301
302
303
304
# File 'lib/taskjuggler/TjTime.rb', line 297

def sameTimeNextQuarter
  sec, min, hour, day, month, year = localtime.to_a
  if (month += 3) > 12
    month -= 12
    year += 1
  end
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#sameTimeNextWeekObject

Return a new time that is 1 week later than time but at the same time of day.



270
271
272
273
274
275
276
277
278
279
280
# File 'lib/taskjuggler/TjTime.rb', line 270

def sameTimeNextWeek
  sec, min, hour, day, month, year = localtime.to_a
  if (day += 7) > lastDayOfMonth(month, year)
    day -= lastDayOfMonth(month, year)
    if (month += 1) > 12
      month = 1
      year += 1
    end
  end
  TjTime.new([ year, month, day, hour, min, sec, 0 ])
end

#sameTimeNextYearObject

Return a new time that is 1 year later than time but at the same time of day.



308
309
310
311
312
# File 'lib/taskjuggler/TjTime.rb', line 308

def sameTimeNextYear
  sec, min, hour, day, month, year = localtime.to_a
  year += 1
  TjTime.new([ year, month, day, hour, min, sec, 0])
end

#secondsOfDay(tz = nil) ⇒ Object

Returns the total number of seconds of the day. The time is assumed to be in the time zone specified by tz.



119
120
121
122
# File 'lib/taskjuggler/TjTime.rb', line 119

def secondsOfDay(tz = nil)
  lt = localtime
  (lt.to_i + lt.gmt_offset) % (60 * 60 * 24)
end

#strftime(format) ⇒ Object



389
390
391
# File 'lib/taskjuggler/TjTime.rb', line 389

def strftime(format)
  localtime.strftime(format)
end

#to_aObject



385
386
387
# File 'lib/taskjuggler/TjTime.rb', line 385

def to_a
  localtime.to_a
end

#to_iObject

Return the seconds since Epoch.



381
382
383
# File 'lib/taskjuggler/TjTime.rb', line 381

def to_i
  localtime.to_i
end

#to_s(format = nil, tz = nil) ⇒ Object

This function is just a wrapper around Time.strftime(). In case @time is nil, it returns ‘unkown’.



366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/taskjuggler/TjTime.rb', line 366

def to_s(format = nil, tz = nil)
  return 'unknown' if @time.nil?

  t = tz == 'UTC' ? gmtime : localtime
  if format.nil?
    fmt = '%Y-%m-%d-%H:%M' + (@time.sec == 0 ? '' : ':%S') + '-%z'
  else
    # Handle TJ specific extensions to the strftime format.
    fmt = format.sub(/%Q/, "#{((t.mon - 1) / 3) + 1}")
  end
  # Always report values in local timezone
  t.strftime(fmt)
end

#upto(endDate, step = 1) ⇒ Object

Iterator that executes the block until time has reached endDate increasing time by step on each iteration.



182
183
184
185
186
187
188
# File 'lib/taskjuggler/TjTime.rb', line 182

def upto(endDate, step = 1)
  t = @time
  while t < endDate.time
    yield(TjTime.new(t))
    t += step
  end
end

#utcObject

Return the time object in UTC.



113
114
115
# File 'lib/taskjuggler/TjTime.rb', line 113

def utc
  TjTime.new(@time.dup.gmtime)
end

#wdayObject

Return the day of the week. 0 for Sunday, 1 for Monday and so on.



394
395
396
# File 'lib/taskjuggler/TjTime.rb', line 394

def wday
  localtime.wday
end

#weeksTo(date) ⇒ Object

Return the number of weeks between this time and date. The result is always rounded up.



342
343
344
# File 'lib/taskjuggler/TjTime.rb', line 342

def weeksTo(date)
  countIntervals(date, :sameTimeNextWeek)
end

#yearObject

Return the year.



416
417
418
# File 'lib/taskjuggler/TjTime.rb', line 416

def year
  localtime.year
end

#yearsTo(date) ⇒ Object

Return the number of years between this time and date. The result is always rounded up.



360
361
362
# File 'lib/taskjuggler/TjTime.rb', line 360

def yearsTo(date)
  countIntervals(date, :sameTimeNextYear)
end