Class: Tilia::VObject::Property::ICalendar::DateTime

Inherits:
Tilia::VObject::Property show all
Defined in:
lib/tilia/v_object/property/i_calendar/date_time.rb

Overview

DateTime property.

This object represents DATE-TIME values, as defined here:

tools.ietf.org/html/rfc5545#section-3.3.4

This particular object has a bit of hackish magic that it may also in some cases represent a DATE value. This is because it’s a common usecase to be able to change a DATE-TIME into a DATE.

Direct Known Subclasses

Date

Constant Summary

Constants inherited from Node

Node::PROFILE_CALDAV, Node::PROFILE_CARDDAV, Node::REPAIR

Instance Attribute Summary collapse

Attributes inherited from Tilia::VObject::Property

#group, #name, #parameters, #value

Attributes inherited from Node

#iterator, #parent

Instance Method Summary collapse

Methods inherited from Tilia::VObject::Property

#==, #[], #add, #delete, #destroy, #initialize_copy, #json_serialize, #key?, #parts, #serialize, #to_s, #xml_serialize, #xml_value=

Methods inherited from Node

#==, #[], #delete, #destroy, #each, #json_serialize, #key?, #serialize, #size, #xml_serialize

Constructor Details

#initialize(*args) ⇒ DateTime

Returns a new instance of DateTime.



245
246
247
248
249
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 245

def initialize(*args)
  super
  @delimiter = ','
  @raw_values = []
end

Instance Attribute Details

#delimiterString?

In case this is a multi-value property. This string will be used as a delimiter.

Returns:

  • (String, nil)


19
20
21
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 19

def delimiter
  @delimiter
end

Instance Method Details

#[]=(name, value) ⇒ void

This method returns an undefined value.

We need to intercept offsetSet, because it may be used to alter the VALUE from DATE-TIME to DATE or vice-versa.

Parameters:

  • name (String)
  • value


208
209
210
211
212
213
214
215
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 208

def []=(name, value)
  super

  return nil unless name.upcase == 'VALUE'

  # This will ensure that dates are correctly encoded.
  update_date_times(date_times)
end

#date_time(time_zone = nil) ⇒ Time

Returns a date-time value.

Note that if this property contained more than 1 date-time, only the first will be returned. To get an array with multiple values, call getDateTimes.

If no timezone information is known, because it’s either an all-day property or floating time, we will use the DateTimeZone argument to figure out the exact date.

Parameters:

  • time_zone (ActiveSupport::TimeZone) (defaults to: nil)

Returns:



101
102
103
104
105
106
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 101

def date_time(time_zone = nil)
  dt = date_times(time_zone)
  return nil unless dt

  dt[0]
end

#date_time=(dt) ⇒ void

This method returns an undefined value.

Sets the property as a DateTime object.

Parameters:

  • dt (Time)
  • isFloating (Boolean)

    If set to true, timezones will be ignored.



137
138
139
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 137

def date_time=(dt)
  self.date_times = [dt]
end

#date_times(time_zone = nil) ⇒ DateTimeImmutable[], \DateTime[]

Returns multiple date-time values.

If no timezone information is known, because it’s either an all-day property or floating time, we will use the DateTimeZone argument to figure out the exact date.

Parameters:

  • time_zone (ActiveSupport::TimeZone) (defaults to: nil)

Returns:



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 118

def date_times(time_zone = nil)
  # Does the property have a TZID?
  tzid = self['TZID']

  time_zone = Tilia::VObject::TimeZoneUtil.time_zone(tzid.to_s, @root) if tzid

  dts = []
  parts.each do |part|
    dts << Tilia::VObject::DateTimeParser.parse(part, time_zone)
  end
  dts
end

#date_times=(dt) ⇒ void

This method returns an undefined value.

Sets the property as multiple date-time objects.

The first value will be used as a reference for the timezones, and all the otehr values will be adjusted for that timezone

Parameters:

  • dt (DateTimeInterface[])
  • isFloating (Boolean)

    If set to true, timezones will be ignored.



150
151
152
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 150

def date_times=(dt)
  update_date_times(dt)
end

#floatingObject



291
292
293
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 291

def floating
  floating?
end

#floating=(is_floating) ⇒ Object



295
296
297
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 295

def floating=(is_floating)
  update_date_times(date_times, is_floating)
end

#floating?Boolean

Returns true if this is a floating DATE or DATE-TIME.

Note that DATE is always floating.

Returns:



84
85
86
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 84

def floating?
  !self.time? || (!self.key?('TZID') && !value.index('Z'))
end

#json_valuearray

Returns the value, in the format it should be encoded for JSON.

This method must always return an array.

Returns:

  • (array)


169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 169

def json_value
  dts = date_times

  tz = dts[0].time_zone
  is_utc = floating? ? false : ['UTC', 'GMT', 'Z'].include?(tz.name)

  dts.map do |dt|
    if time?
      dt.strftime('%Y-%m-%dT%H:%M:%S') + (is_utc ? 'Z' : '')
    else
      dt.strftime('%Y-%m-%d')
    end
  end
end

#json_value=(value) ⇒ void

This method returns an undefined value.

Sets the json value, as it would appear in a jCard or jCal object.

The value must always be an array.

Parameters:

  • value (array)


191
192
193
194
195
196
197
198
199
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 191

def json_value=(value)
  # dates and times in jCal have one difference to dates and times in
  # iCalendar. In jCal date-parts are separated by dashes, and
  # time-parts are separated by colons. It makes sense to just remove
  # those.
  self.value = value.map do |item|
    item.delete(':').delete('-')
  end
end

#parts=(parts) ⇒ void

This method returns an undefined value.

Sets a multi-valued property.

You may also specify DateTime objects here.

Parameters:

  • parts (array)


28
29
30
31
32
33
34
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 28

def parts=(parts)
  if parts[0].is_a?(::Time)
    self.date_times = parts
  else
    super(parts)
  end
end

#raw_mime_dir_valueString

Returns a raw mime-dir representation of the value.

Returns:

  • (String)


70
71
72
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 70

def raw_mime_dir_value
  parts.join(@delimiter)
end

#raw_mime_dir_value=(val) ⇒ void

This method returns an undefined value.

Sets a raw value coming from a mimedir (iCalendar/vCard) file.

This has been ‘unfolded’, so only 1 line will be passed. Unescaping is not yet done, but parameters are not included.

Parameters:

  • val (String)


63
64
65
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 63

def raw_mime_dir_value=(val)
  self.value = val.split(@delimiter)
end

#time?Boolean

Returns true if this is a DATE-TIME value, false if it’s a DATE.

Returns:



77
78
79
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 77

def time?
  self['VALUE'].to_s.upcase != 'DATE'
end

#update_date_times(dt, is_floating = false) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 251

def update_date_times(dt, is_floating = false)
  values = []

  if time?
    tz = nil
    is_utc = false

    dt.each do |d|
      if is_floating
        values << d.strftime('%Y%m%dT%H%M%S')
        next
      end

      if tz.nil?
        tz = d.time_zone
        is_utc = ['UTC', 'GMT', 'Z', '+00:00'].include?(tz.name)

        self['TZID'] = tz.name unless is_utc
      else
        d = d.in_time_zone(tz)
      end

      if is_utc
        values << d.strftime('%Y%m%dT%H%M%SZ')
      else
        values << d.strftime('%Y%m%dT%H%M%S')
      end
    end

    delete('TZID') if is_utc || is_floating
  else
    dt.each do |d|
      values << d.strftime('%Y%m%d')
    end
    delete('TZID')
  end

  @value = values
end

#validate(options = 0) ⇒ array

Validates the node for correctness.

The following options are supported:

Node::REPAIR - May attempt to automatically repair the problem.
Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.

This method returns an array with detected problems. Every element has the following properties:

* level - problem level.
* message - A human-readable string describing the issue.
* node - A reference to the problematic node.

The level means:

1 - The issue was repaired (only happens if REPAIR was turned on).
2 - A warning.
3 - An error.

Parameters:

  • options (Fixnum) (defaults to: 0)

Returns:

  • (array)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 218

def validate(options = 0)
  messages = super(options)
  value_type = self.value_type
  values = parts

  begin
    save_val = nil
    values.each do |value|
      save_val = value
      case value_type
      when 'DATE'
        Tilia::VObject::DateTimeParser.parse_date(value)
      when 'DATE-TIME'
        Tilia::VObject::DateTimeParser.parse_date_time(value)
      end
    end
  rescue InvalidDataException
    messages << {
      'level'   => 3,
      'message' => "The supplied value (#{save_val}) is not a correct #[value_type}",
      'node'    => self
    }
  end

  messages
end

#value=(value) ⇒ void

This method returns an undefined value.

Updates the current value.

This may be either a single, or multiple strings in an array.

Instead of strings, you may also use DateTime here.

Parameters:

  • value (String|array|DateTimeInterface)


45
46
47
48
49
50
51
52
53
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 45

def value=(value)
  if value.is_a?(Array) && value[0].is_a?(::Time)
    self.date_times = value
  elsif value.is_a?(::Time)
    self.date_times = [value]
  else
    super(value)
  end
end

#value_typeString

Returns the type of value.

This corresponds to the VALUE= parameter. Every property also has a ‘default’ valueType.

Returns:

  • (String)


160
161
162
# File 'lib/tilia/v_object/property/i_calendar/date_time.rb', line 160

def value_type
  time? ? 'DATE-TIME' : 'DATE'
end