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.



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

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.



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

def time
  @time
end

Class Method Details

.checkTimeZone(zone) ⇒ Object

Check if zone is a valid time zone.



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
86
# File 'lib/taskjuggler/TjTime.rb', line 61

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.



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

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.



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

def TjTime.timeZone
  @@tz
end

Instance Method Details

#%(val) ⇒ Object

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



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

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

#+(secs) ⇒ Object

Add secs number of seconds to the time.



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

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.



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

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.



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

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

#<=(t) ⇒ Object

Return true if time is smaller or equal than t.



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

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

#<=>(t) ⇒ Object

Coparison operator for time with another time t.



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

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

#==(t) ⇒ Object

Return true if time and t are identical.



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

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

#>(t) ⇒ Object

Return true if time is larger than t.



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

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

#>=(t) ⇒ Object

Return true if time is larger or equal than t.



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

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.



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

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

#beginOfHourObject

Normalize time to the beginning of the current hour.



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

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.



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

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.



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

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.



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

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.



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

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).



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

def day
  localtime.day
end

#daysTo(date) ⇒ Object

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



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

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

#hourObject

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



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

def hour
  localtime.hour
end

#hoursLater(hours) ⇒ Object

Return a new time that is hours later than time.



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

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.



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

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

#midnightObject

Normalize time to the beginning of the current day.



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

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)



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

def month
  localtime.month
end

#monthsTo(date) ⇒ Object

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



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

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.



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

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.



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

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.



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

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.



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

def sameTimeNextHour
  hoursLater(1)
end

#sameTimeNextMonthObject

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



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

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.



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

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.



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

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.



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

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.



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

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

#strftime(format) ⇒ Object



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

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

#to_aObject



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

def to_a
  localtime.to_a
end

#to_iObject

Return the seconds since Epoch.



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

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’.



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

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.



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

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.



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

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

#wdayObject

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



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

def wday
  localtime.wday
end

#weeksTo(date) ⇒ Object

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



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

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

#yearObject

Return the year.



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

def year
  localtime.year
end

#yearsTo(date) ⇒ Object

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



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

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