Commit cdb5fd21 authored by Sebastian's avatar Sebastian
Browse files

Merge pull request #33 from takkaria/timezone-fixes

Timezone fixes
parents b76ed63e c89a71d0
...@@ -271,7 +271,7 @@ Empty the Calender. ...@@ -271,7 +271,7 @@ Empty the Calender.
#### uid([_String_|_Number_ uid]) or id([_String_|_Number_ id]) #### uid([_String_|_Number_ uid]) or id([_String_|_Number_ id])
Use this method to set the event's ID. If not set, an UID will be generated randomly. Use this method to set the event's ID. If not set, an UID will be generated randomly. When output, the ID will be suffixed with '@' + your calendar's domain.
#### start([_Date_ start]) #### start([_Date_ start])
...@@ -284,6 +284,13 @@ Appointment date of beginning as Date object. This is required for all events! ...@@ -284,6 +284,13 @@ Appointment date of beginning as Date object. This is required for all events!
Appointment date of end as Date object. Appointment date of end as Date object.
#### timezone([_String_ timezone])
Use this method to set your event's timezone using the TZID property parameter on start and end dates, as per [date-time form #3 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5).
This and the 'floating' flag (see below) are mutually exclusive, and setting a timezone will unset the 'floating' flag. If neither 'timezone' nor 'floating' are set, the date will be output with in UTC format (see [date-time form #2 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5)).
#### timestamp([_Date_ stamp]) or stamp([_Date_ stamp]) #### timestamp([_Date_ stamp]) or stamp([_Date_ stamp])
Appointment date of creation as Date object. Default to `new Date()`. Appointment date of creation as Date object. Default to `new Date()`.
...@@ -295,6 +302,7 @@ When allDay == true -> appointment is for the whole day ...@@ -295,6 +302,7 @@ When allDay == true -> appointment is for the whole day
#### floating([_Boolean_ floating]) #### floating([_Boolean_ floating])
Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.12): Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.12):
> Time values of this type are said to be "floating" and are not > Time values of this type are said to be "floating" and are not
...@@ -305,8 +313,11 @@ Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools ...@@ -305,8 +313,11 @@ Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools
> AM to 1:00 PM every day, no matter which time zone the person is > AM to 1:00 PM every day, no matter which time zone the person is
> in. In these cases, a local time can be specified. > in. In these cases, a local time can be specified.
This and the 'timezone' setting (see above) are mutually exclusive, and setting the floating flag will unset the 'timezone'. If neither 'timezone' nor 'floating' are set, the date will be output with in UTC format (see [date-time form #2 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5)).
#### repeating([_Object_ repeating]) #### repeating([_Object_ repeating])
Appointment is a repeating event Appointment is a repeating event
```javascript ```javascript
......
...@@ -27,6 +27,23 @@ module.exports.formatDate = function formatDate(d, dateonly, floating) { ...@@ -27,6 +27,23 @@ module.exports.formatDate = function formatDate(d, dateonly, floating) {
return s; return s;
}; };
// For information about this format, see RFC 5545, section 3.3.5
// https://tools.ietf.org/html/rfc5545#section-3.3.5
module.exports.formatDateTZ = function formatDateTZ(property, date, eventData) {
var tzParam = '';
var floating = eventData.floating;
if(eventData.timezone) {
tzParam = ';TZID=' + eventData.timezone;
// This isn't a 'floating' event because it has a timezone;
// but we use it to omit the 'Z' UTC specifier in formatDate()
floating = true;
}
return property + tzParam + ':' + module.exports.formatDate(date, false, floating);
};
module.exports.escape = function escape(str) { module.exports.escape = function escape(str) {
return str.replace(/[\\;,"]/g, function(match) { return str.replace(/[\\;,"]/g, function(match) {
return '\\' + match; return '\\' + match;
......
...@@ -285,11 +285,6 @@ var ICalCalendar = function(_data) { ...@@ -285,11 +285,6 @@ var ICalCalendar = function(_data) {
throw 'event.start is a mandatory item!'; throw 'event.start is a mandatory item!';
} }
// validation: end
if(!event.end) {
throw 'event.end is a mandatory item!';
}
// validation: summary // validation: summary
if(!event.summary) { if(!event.summary) {
throw 'event.summary is a mandatory item!'; throw 'event.summary is a mandatory item!';
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* @constructor ICalEvent Event * @constructor ICalEvent Event
*/ */
var ICalEvent = function(_data) { var ICalEvent = function(_data) {
var attributes = ['id', 'uid', 'start', 'end', 'stamp', 'timestamp', 'allDay', 'floating', 'repeating', 'summary', 'location', 'description', 'organizer', 'attendees', 'alarms', 'method', 'status', 'url'], var attributes = ['id', 'uid', 'start', 'end', 'timezone', 'stamp', 'timestamp', 'allDay', 'floating', 'repeating', 'summary', 'location', 'description', 'organizer', 'attendees', 'alarms', 'method', 'status', 'url'],
vars, vars,
i, i,
data; data;
...@@ -22,6 +22,7 @@ var ICalEvent = function(_data) { ...@@ -22,6 +22,7 @@ var ICalEvent = function(_data) {
id: ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).substr(-4), id: ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).substr(-4),
start: null, start: null,
end: null, end: null,
timezone: null,
stamp: new Date(), stamp: new Date(),
allDay: false, allDay: false,
floating: false, floating: false,
...@@ -124,6 +125,26 @@ var ICalEvent = function(_data) { ...@@ -124,6 +125,26 @@ var ICalEvent = function(_data) {
}; };
/**
* Set/Get the event's timezone. This unsets the event's floating flag.
* Used on date properties
*
* @param [timezone] Timezone
* @example event.timezone('America/New_York');
* @since 0.2.6
* @returns {ICalEvent|String}
*/
this.timezone = function(timezone) {
if(!timezone) {
return data.timezone;
}
data.timezone = timezone.toString();
data.floating = false;
return this;
};
/** /**
* Set/Get the event's timestamp * Set/Get the event's timestamp
* *
...@@ -176,7 +197,7 @@ var ICalEvent = function(_data) { ...@@ -176,7 +197,7 @@ var ICalEvent = function(_data) {
/** /**
* Set/Get the event's floating flag * Set/Get the event's floating flag. This unsets the event's timezone.
* See https://tools.ietf.org/html/rfc5545#section-3.3.12 * See https://tools.ietf.org/html/rfc5545#section-3.3.12
* *
* @param {Boolean} floating * @param {Boolean} floating
...@@ -189,6 +210,7 @@ var ICalEvent = function(_data) { ...@@ -189,6 +210,7 @@ var ICalEvent = function(_data) {
} }
data.floating = !!floating; data.floating = !!floating;
data.timezone = null;
return this; return this;
}; };
...@@ -573,9 +595,9 @@ var ICalEvent = function(_data) { ...@@ -573,9 +595,9 @@ var ICalEvent = function(_data) {
g += 'DTEND;VALUE=DATE:' + tools.formatDate(data.end, true) + '\r\n'; g += 'DTEND;VALUE=DATE:' + tools.formatDate(data.end, true) + '\r\n';
} }
} else { } else {
g += 'DTSTART:' + tools.formatDate(data.start, false, data.floating) + '\r\n'; g += tools.formatDateTZ('DTSTART', data.start, data) + '\r\n';
if (data.end) { if (data.end) {
g += 'DTEND:' + tools.formatDate(data.end, false, data.floating) + '\r\n'; g += tools.formatDateTZ('DTEND', data.end, data) + '\r\n';
} }
} }
......
...@@ -185,17 +185,6 @@ describe('ical-generator 0.1.x', function() { ...@@ -185,17 +185,6 @@ describe('ical-generator 0.1.x', function() {
}, /event\.start must be a Date Object/); }, /event\.start must be a Date Object/);
}); });
it('should throw error when no end time given', function() {
var generator = require(__dirname + '/../lib/index.js'),
cal = generator();
assert.throws(function() {
cal.addEvent({
start: new Date()
});
}, /event\.end is a mandatory item/);
});
it('should throw error when end time is not a date', function() { it('should throw error when end time is not a date', function() {
var generator = require(__dirname + '/../lib/index.js'), var generator = require(__dirname + '/../lib/index.js'),
cal = generator(); cal = generator();
......
...@@ -147,7 +147,7 @@ describe('ical-generator 0.2.x / ICalCalendar', function() { ...@@ -147,7 +147,7 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
assert.equal(cal.timezone(), 'Europe/Berlin'); assert.equal(cal.timezone(), 'Europe/Berlin');
}); });
it('should change something', function() { it('should make a difference to iCal output', function() {
var cal = ical().timezone('Europe/London'); var cal = ical().timezone('Europe/London');
cal.createEvent({ cal.createEvent({
start: new Date(), start: new Date(),
...@@ -156,6 +156,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() { ...@@ -156,6 +156,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
}); });
assert.ok(cal.toString().indexOf('Europe/London') > -1); assert.ok(cal.toString().indexOf('Europe/London') > -1);
}); });
it('should mark event as not floating', function() {
var cal = ical().timezone('Europe/London'),
evt = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event',
floating: true
});
evt.timezone('Europe/Berlin');
assert.equal(evt.floating(), false);
});
}); });
describe('ttl()', function() { describe('ttl()', function() {
...@@ -216,6 +230,15 @@ describe('ical-generator 0.2.x / ICalCalendar', function() { ...@@ -216,6 +230,15 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
assert.equal(event.summary(), 'Patch-Day'); assert.equal(event.summary(), 'Patch-Day');
}); });
it('should not require optional parameters', function() {
assert.doesNotThrow(function () {
ical().addEvent({
start: new Date(),
summary: 'Patch-Day'
});
}, Error);
});
}); });
describe('events()', function() { describe('events()', function() {
...@@ -467,6 +490,30 @@ describe('ical-generator 0.2.x / ICalCalendar', function() { ...@@ -467,6 +490,30 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
}); });
}); });
describe('timezone()', function() {
it('setter should return this', function() {
var e = ical().createEvent();
assert.deepEqual(e, e.timezone('Europe/Berlin'));
});
it('getter should return value', function() {
var e = ical().createEvent().timezone('Europe/Berlin');
assert.equal(e.timezone(), 'Europe/Berlin');
});
it('should change something', function() {
var cal = ical(),
e = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event'
});
e.timezone('Europe/London');
assert.ok(cal.toString().indexOf('Europe/London') > -1);
});
});
describe('stamp()', function() { describe('stamp()', function() {
it('setter should return this', function() { it('setter should return this', function() {
var e = ical().createEvent(); var e = ical().createEvent();
...@@ -555,6 +602,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() { ...@@ -555,6 +602,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
event.floating(true); event.floating(true);
assert.ok(str !== cal.toString()); assert.ok(str !== cal.toString());
}); });
it('should mark event as having no time zone', function() {
var cal = ical().timezone('Europe/London'),
evt = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event',
timezone: 'Europe/Berlin'
});
evt.floating(true);
assert.equal(evt.timezone(), null);
});
}); });
describe('repeating()', function() { describe('repeating()', function() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment