From 96bb5592b99778d719bf074a4c6dea43b1a3105d Mon Sep 17 00:00:00 2001 From: Arthur Sieler Date: Thu, 26 May 2016 17:05:40 -0400 Subject: [PATCH 01/11] added startOf/endOf --- moment.cfc | 51 +++++++++++++++++++++++++++++++++++++++++ tests/testbox/tests.cfc | 30 +++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/moment.cfc b/moment.cfc index 137c633..fe4d7fd 100644 --- a/moment.cfc +++ b/moment.cfc @@ -62,7 +62,48 @@ component displayname="moment" { public function subtract( required numeric amount, required string part ){ return add( -1 * amount, part ); } + + public function startOf( required string part ){ + part = canonicalizeDatePart(part, "startOf"); + switch (part){ + case 'year': + this.time = createDateTime(year(this.time),1,day(this.time),hour(this.time),minute(this.time),second(this.time)); + case 'quarter': + case 'month': + this.time = createDateTime(year(this.time),month(this.time),1,hour(this.time),minute(this.time),second(this.time)); + case 'week': + case 'day': + this.time = createDateTime(year(this.time),month(this.time),day(this.time),0,minute(this.time),second(this.time)); + case 'hour': + this.time = createDateTime(year(this.time),month(this.time),day(this.time),hour(this.time),0,second(this.time)); + case 'minute': + this.time = createDateTime(year(this.time),month(this.time),day(this.time),hour(this.time),minute(this.time),0); + } + + // weeks are a special case + if (part is "week"){ + this.time = dateAdd("d",(dayOfWeek(this.time)-1)*-1,this.time); + } + + // quarters are also special + if (part is "quarter"){ + this.time = createDateTime(year(this.time),int(month(this.time)/3)*3+1,day(this.time),hour(this.time),minute(this.time),second(this.time)); + } + + return this; + } + + public function endOf(required string part) { + part = canonicalizeDatePart(part, "startOf"); + + if (part is "millisecond"){ + return this; + } + + return this.startOf(part).add(1,part).subtract(1,"ms"); + } + //=========================================== //STATICS //=========================================== @@ -275,29 +316,35 @@ component displayname="moment" { var isDateAdd = (lcase(method) == 'dateadd'); var isDateDiff = (lcase(method) == 'datediff'); var isDateCompare = (lcase(method) == 'datecompare'); + var isStartOf = (lcase(method) == 'startof'); switch( lcase(arguments.part) ){ case 'years': case 'year': case 'y': + if (isStartOf) return 'year'; return 'yyyy'; case 'quarters': case 'quarter': case 'q': + if (isStartOf) return 'quarter'; if (!isDateCompare) return 'q'; throw(message='DateCompare doesn''t support Quarter precision'); case 'months': case 'month': case 'm': + if (isStartOf) return 'month'; return 'm'; case 'weeks': case 'week': case 'w': + if (isStartOf) return 'week'; if (!isDateCompare) return 'ww'; throw(message='DateCompare doesn''t support Week precision'); case 'days': case 'day': case 'd': + if (isStartOf) return 'day'; return 'd'; case 'weekdays': case 'weekday': @@ -307,18 +354,22 @@ component displayname="moment" { case 'hours': case 'hour': case 'h': + if (isStartOf) return 'hour'; return 'h'; case 'minutes': case 'minute': case 'n': + if (isStartOf) return 'minute'; return 'n'; case 'seconds': case 'second': case 's': + if (isStartOf) return 'second'; return 's'; case 'milliseconds': case 'millisecond': case 'ms': + if (isStartOf) return 'millisecond'; if (isDateAdd) return 'L'; if (isDateDiff) return 'L'; //custom support for ms diffing is provided interally, because adobe sucks throw(message='#method# doesn''t support Millisecond precision'); diff --git a/tests/testbox/tests.cfc b/tests/testbox/tests.cfc index a582a40..e974a9a 100644 --- a/tests/testbox/tests.cfc +++ b/tests/testbox/tests.cfc @@ -53,7 +53,7 @@ component extends="testbox.system.BaseSpec" { }); describe("MUTATORS", function(){ - + describe("utc()", function(){ it("correctly calculates the utc value", function(){ outsideDST = moment('2015-02-01 00:00:00', 'America/New_York').utc(); @@ -345,6 +345,34 @@ component extends="testbox.system.BaseSpec" { }); }); + + describe("startOf()", function(){ + it("supports masks: year, quarter, month, week, day and minute", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); + + expect( start.startOf("year").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-01 00:00:00" ); + expect( start.startOf("quarter").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-01 00:00:00" ); + expect( start.startOf("month").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-01 00:00:00" ); + expect( start.startOf("week").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-31 00:00:00" ); + expect( start.startOf("day").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:00:00" ); + expect( start.startOf("hour").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:00:00" ); + expect( start.startOf("minute").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:05:00" ); + }); + }); + + describe("endOf()", function(){ + it("supports masks: year, quarter, month, week, day and minute", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); + + expect( start.endOf("year").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-12-31 23:59:59" ); + expect( start.endOf("quarter").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-03-31 23:59:59" ); + expect( start.endOf("month").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-29 23:59:59" ); + expect( start.endOf("week").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-06 23:59:59" ); + expect( start.endOf("day").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 23:59:59" ); + expect( start.endOf("hour").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:59:59" ); + expect( start.endOf("minute").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:05:59" ); + }); + }); }); From c7a0012e0599b9ab039d7f52a6e0a74b2b281993 Mon Sep 17 00:00:00 2001 From: Arthur Sieler Date: Thu, 26 May 2016 17:27:59 -0400 Subject: [PATCH 02/11] fixed issue with date format --- moment.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moment.cfc b/moment.cfc index fe4d7fd..bb3ca15 100644 --- a/moment.cfc +++ b/moment.cfc @@ -177,7 +177,7 @@ component displayname="moment" { mask = mask; } - return dateTimeFormat( this.localTime, mask, this.zone ); + return dateTimeFormat( this.time, mask, this.zone ); } public function from( required moment compare ) hint="returns fuzzy-date string e.g. 2 hours ago" { From acb1fa2a719e4c16bf767a6f58ba91fee2379e28 Mon Sep 17 00:00:00 2001 From: Arthur Sieler Date: Thu, 9 Jun 2016 18:38:21 -0400 Subject: [PATCH 03/11] added ability to accept epoch when moment is initialized --- moment.cfc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/moment.cfc b/moment.cfc index 137c633..5d0dc52 100644 --- a/moment.cfc +++ b/moment.cfc @@ -26,7 +26,11 @@ component displayname="moment" { -- for instance initialized to someTimeValue in someTZID TZ */ public function init( time = now(), zone = getSystemTZ() ) { - this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + if (isNumeric(time)) + this.time = epochToDate(arguments.time); + else + this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + this.zone = zone; this.utc_conversion_offset = getTargetOffsetDiff( getSystemTZ(), zone, time ); this.utcTime = TZtoUTC( arguments.time, arguments.zone ); @@ -244,7 +248,17 @@ component displayname="moment" { //=========================================== //INTERNAL HELPERS //=========================================== + + private function epochToDate( epoch ){ + var d = ""; + if (isValid("integer",arguments.epoch)) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch*1000)); + else if (isNumeric(arguments.epoch) and val(arguments.epoch) gt 1000) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch)); + return d; + } + private function getSystemTimeMS(){ return createObject('java', 'java.lang.System').currentTimeMillis(); } From 40db42b5365388bb1536994ad3647fbf69c814a4 Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Fri, 10 Jun 2016 08:54:12 -0400 Subject: [PATCH 04/11] Removing ntp date config request that crashes every test --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24598c1..28b008f 100755 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ env: before_install: - echo 'Canada/Pacific' | sudo tee /etc/timezone - sudo dpkg-reconfigure --frontend noninteractive tzdata - - sudo ntpdate ntp.ubuntu.com install: ant -Dtest.framework=$TESTFRAMEWORK -Dsource=remote -Dwork.dir=$HOME/work -Dbuild.dir=$TRAVIS_BUILD_DIR -Dplatform=$PLATFORM install-ci-deps script: ant -Dtest.framework=$TESTFRAMEWORK -Dsource=remote -Dwork.dir=$HOME/work -Dbuild.dir=$TRAVIS_BUILD_DIR -Dplatform=$PLATFORM test-ci From 5660aa10fb230cc9544d0dd2c111281471ac504d Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Fri, 10 Jun 2016 08:58:12 -0400 Subject: [PATCH 05/11] updating test to reflect recently updated logic --- tests/testbox/tests.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testbox/tests.cfc b/tests/testbox/tests.cfc index a582a40..d270d8b 100644 --- a/tests/testbox/tests.cfc +++ b/tests/testbox/tests.cfc @@ -700,7 +700,7 @@ component extends="testbox.system.BaseSpec" { it("detects single months", function(){ var test = base.clone().add( 1, 'months' ).add( 3, 'days' ); var test2 = base.clone().add( 1, 'months' ).subtract( 3, 'days' ); - expect( test.from( base ) ).toBe( '1 month ago' ); + expect( test.from( base ) ).toBe( '4 weeks ago' ); }); it("detects multiple weeks", function(){ From c27175d1c23dcca5a9dee0ad604bd430c51ba3f9 Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Mon, 13 Jun 2016 17:27:49 -0400 Subject: [PATCH 06/11] Fix logic bugs in startOf/endOf and flesh out the tests more --- moment.cfc | 77 +++++++++++++++++++++++++++++------------ tests/testbox/tests.cfc | 68 +++++++++++++++++++++++++++++++----- 2 files changed, 114 insertions(+), 31 deletions(-) diff --git a/moment.cfc b/moment.cfc index bb3ca15..01eb957 100644 --- a/moment.cfc +++ b/moment.cfc @@ -62,48 +62,79 @@ component displayname="moment" { public function subtract( required numeric amount, required string part ){ return add( -1 * amount, part ); } - + public function startOf( required string part ){ part = canonicalizeDatePart(part, "startOf"); + var dest = ''; switch (part){ case 'year': - this.time = createDateTime(year(this.time),1,day(this.time),hour(this.time),minute(this.time),second(this.time)); + dest = createDateTime(year(this.localTime),1,1,0,0,0); + break; case 'quarter': + dest = createDateTime(year(this.localTime),(int((month(this.localTime)-1)/3)+1)*3-2,1,0,0,0); + break; case 'month': - this.time = createDateTime(year(this.time),month(this.time),1,hour(this.time),minute(this.time),second(this.time)); + dest = createDateTime(year(this.localTime),month(this.localTime),1,0,0,0); + break; case 'week': + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),0,0,0); + dest = dateAdd("d", (dayOfWeek(dest)-1)*-1, dest); + break; case 'day': - this.time = createDateTime(year(this.time),month(this.time),day(this.time),0,minute(this.time),second(this.time)); + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),0,0,0); + break; case 'hour': - this.time = createDateTime(year(this.time),month(this.time),day(this.time),hour(this.time),0,second(this.time)); + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),hour(this.localTime),0,0); + break; case 'minute': - this.time = createDateTime(year(this.time),month(this.time),day(this.time),hour(this.time),minute(this.time),0); - } - - // weeks are a special case - if (part is "week"){ - this.time = dateAdd("d",(dayOfWeek(this.time)-1)*-1,this.time); - } - - // quarters are also special - if (part is "quarter"){ - this.time = createDateTime(year(this.time),int(month(this.time)/3)*3+1,day(this.time),hour(this.time),minute(this.time),second(this.time)); + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),hour(this.localTime),minute(this.localTime),0); + break; + default: + throw(message="Invalid date part value, expected one of: year, quarter, month, week, day, hour, minute; or one of their acceptable aliases (see dateTimeFormat docs)"); } - return this; + return init( dest, this.zone ); } - + public function endOf(required string part) { part = canonicalizeDatePart(part, "startOf"); - if (part is "millisecond"){ - return this; + var dest = ''; + switch (part){ + case 'year': + dest = createDateTime(year(this.localTime),12,31,23,59,59); + break; + case 'quarter': + dest = createDateTime(year(this.localTime),(int((month(this.localTime)-1)/3)+1)*3,1,23,59,59); //first day of last month of quarter (e.g. 12/1) + dest = dateAdd('m', 1, dest); //first day of following month + dest = dateAdd('d', -1, dest); //last day of last month of quarter + break; + case 'month': + dest = createDateTime(year(this.localTime),month(this.localTime),1,23,59,59); //first day of month + dest = dateAdd('m', 1, dest); //first day of following month + dest = dateAdd('d', -1, dest); //last day of target month + break; + case 'week': + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),23,59,59); + dest = dateAdd("d", (7-dayOfWeek(dest)), dest); + break; + case 'day': + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),23,59,59); + break; + case 'hour': + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),hour(this.localTime),59,59); + break; + case 'minute': + dest = createDateTime(year(this.localTime),month(this.localTime),day(this.localTime),hour(this.localTime),minute(this.localTime),59); + break; + default: + throw(message="Invalid date part value, expected one of: year, quarter, month, week, day, hour, minute; or one of their acceptable aliases (see dateTimeFormat docs)"); } - return this.startOf(part).add(1,part).subtract(1,"ms"); + return init( dest, this.zone ); } - + //=========================================== //STATICS //=========================================== @@ -177,7 +208,7 @@ component displayname="moment" { mask = mask; } - return dateTimeFormat( this.time, mask, this.zone ); + return dateTimeFormat( this.localTime, mask, this.zone ); } public function from( required moment compare ) hint="returns fuzzy-date string e.g. 2 hours ago" { diff --git a/tests/testbox/tests.cfc b/tests/testbox/tests.cfc index 8e44cbb..d87aadc 100644 --- a/tests/testbox/tests.cfc +++ b/tests/testbox/tests.cfc @@ -53,7 +53,7 @@ component extends="testbox.system.BaseSpec" { }); describe("MUTATORS", function(){ - + describe("utc()", function(){ it("correctly calculates the utc value", function(){ outsideDST = moment('2015-02-01 00:00:00', 'America/New_York').utc(); @@ -345,31 +345,65 @@ component extends="testbox.system.BaseSpec" { }); }); - + describe("startOf()", function(){ - it("supports masks: year, quarter, month, week, day and minute", function(){ + it("supports masks: year", function(){ start = moment('2016-02-05 00:05:00', 'America/New_York'); - expect( start.startOf("year").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-01 00:00:00" ); + }); + it("supports masks: quarter", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.startOf("quarter").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-01 00:00:00" ); + }); + it("supports masks: month", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.startOf("month").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-01 00:00:00" ); + }); + it("supports masks: week", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.startOf("week").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-01-31 00:00:00" ); + }); + it("supports masks: day", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.startOf("day").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:00:00" ); - expect( start.startOf("hour").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:00:00" ); + }); + it("supports masks: hour", function(){ + start = moment('2016-02-05 03:05:00', 'America/New_York'); + expect( start.startOf("hour").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 03:00:00" ); + }); + it("supports masks: minute", function(){ + start = moment('2016-02-05 00:05:17', 'America/New_York'); expect( start.startOf("minute").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:05:00" ); }); }); describe("endOf()", function(){ - it("supports masks: year, quarter, month, week, day and minute", function(){ + it("supports masks: year", function(){ start = moment('2016-02-05 00:05:00', 'America/New_York'); - expect( start.endOf("year").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-12-31 23:59:59" ); + }); + it("supports masks: quarter", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("quarter").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-03-31 23:59:59" ); + }); + it("supports masks: month", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("month").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-29 23:59:59" ); + }); + it("supports masks: week", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("week").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-06 23:59:59" ); + }); + it("supports masks: day", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("day").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 23:59:59" ); + }); + it("supports masks: hour", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("hour").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:59:59" ); + }); + it("supports masks: minute", function(){ + start = moment('2016-02-05 00:05:00', 'America/New_York'); expect( start.endOf("minute").format("yyyy-mm-dd HH:nn:ss") ).toBe( "2016-02-05 00:05:59" ); }); }); @@ -649,6 +683,7 @@ component extends="testbox.system.BaseSpec" { for(var z in testZones){ var testNoDST = moment( timeNoDST, z.zone ); var testDST = moment( timeDST, z.zone ); + debug( "Testing for: " & z.zone ); debug( testNoDST ); debug( testDST ); @@ -664,6 +699,15 @@ component extends="testbox.system.BaseSpec" { expect( testNoDST.format('dd') ).toBe( '05' ); expect( testNoDST.format('d') ).toBe( '5' ); + expect( testNoDST.format('h') ).toBe( '9' ); + expect( testNoDST.format('hh') ).toBe( '09' ); + expect( testNoDST.format('H') ).toBe( '9' ); + expect( testNoDST.format('HH') ).toBe( '09' ); + expect( testNoDST.format('n') ).toBe( '3' ); + expect( testNoDST.format('nn') ).toBe( '03' ); + expect( testNoDST.format('s') ).toBe( '7' ); + expect( testNoDST.format('ss') ).toBe( '07' ); + expect( testDST.format('yyyy') ).toBe( '2009' ); expect( testDST.format('yy') ).toBe( '09' ); expect( testDST.format('mmmm') ).toBe( 'March' ); @@ -674,7 +718,15 @@ component extends="testbox.system.BaseSpec" { expect( testDST.format('EEE') ).toBe( 'Mon' ); expect( testDST.format('dd') ).toBe( '09' ); expect( testDST.format('d') ).toBe( '9' ); - //more to come here... + + expect( testDST.format('h') ).toBe( '9' ); + expect( testDST.format('hh') ).toBe( '09' ); + expect( testDST.format('H') ).toBe( '9' ); + expect( testDST.format('HH') ).toBe( '09' ); + expect( testDST.format('n') ).toBe( '3' ); + expect( testDST.format('nn') ).toBe( '03' ); + expect( testDST.format('s') ).toBe( '7' ); + expect( testDST.format('ss') ).toBe( '07' ); //now check formattings with time zones expect( testNoDST.format('long') ).toBe( 'March 5, 2009 9:03:07 AM #z.short#' ); From 0f388e5ff6a4a131a3c91ba62bb7aa2247beaa83 Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Mon, 13 Jun 2016 17:32:49 -0400 Subject: [PATCH 07/11] added docs for startof/endof --- readme.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/readme.md b/readme.md index e99373d..b5f1360 100644 --- a/readme.md +++ b/readme.md @@ -51,6 +51,16 @@ Here's a list of all masks you can use with add/subtract: **\* \* Another deviation from the official dateAdd mask:** `ms` just makes more sense than the `l` (lower case L) that Adobe uses. +#### startOf / endOf + +Returns a new moment instance with the date/time shifted to the start or end of the specified date part. For example, the end of the current week: + + endOfWeek = new moment().endOf('week'); + +Or the start of the next quarter: + + nextQuarter = new moment().startOf('quarter').add(1, 'quarter'); + #### Clone Returns a new moment instance with the same datetime and time zone. From d6318fafaec91f3aec3c700fc2940e96f4a3e9f0 Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Mon, 13 Jun 2016 17:34:11 -0400 Subject: [PATCH 08/11] added note about week math --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b5f1360..23b0675 100644 --- a/readme.md +++ b/readme.md @@ -53,7 +53,7 @@ Here's a list of all masks you can use with add/subtract: #### startOf / endOf -Returns a new moment instance with the date/time shifted to the start or end of the specified date part. For example, the end of the current week: +Returns a new moment instance with the date/time shifted to the start or end of the specified date part. For example, the end of the current week*: endOfWeek = new moment().endOf('week'); @@ -61,6 +61,8 @@ Or the start of the next quarter: nextQuarter = new moment().startOf('quarter').add(1, 'quarter'); +**\* Weeks are assumed to be Sun-Sat** + #### Clone Returns a new moment instance with the same datetime and time zone. From 90242ba6aa566729f855db1cdb54cbfa7ca58482 Mon Sep 17 00:00:00 2001 From: Arthur Sieler Date: Thu, 9 Jun 2016 18:38:21 -0400 Subject: [PATCH 09/11] added ability to accept epoch when moment is initialized --- moment.cfc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/moment.cfc b/moment.cfc index 01eb957..931d122 100644 --- a/moment.cfc +++ b/moment.cfc @@ -26,7 +26,11 @@ component displayname="moment" { -- for instance initialized to someTimeValue in someTZID TZ */ public function init( time = now(), zone = getSystemTZ() ) { - this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + if (isNumeric(time)) + this.time = epochToDate(arguments.time); + else + this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + this.zone = zone; this.utc_conversion_offset = getTargetOffsetDiff( getSystemTZ(), zone, time ); this.utcTime = TZtoUTC( arguments.time, arguments.zone ); @@ -316,7 +320,17 @@ component displayname="moment" { //=========================================== //INTERNAL HELPERS //=========================================== + + private function epochToDate( epoch ){ + var d = ""; + if (isValid("integer",arguments.epoch)) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch*1000)); + else if (isNumeric(arguments.epoch) and val(arguments.epoch) gt 1000) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch)); + return d; + } + private function getSystemTimeMS(){ return createObject('java', 'java.lang.System').currentTimeMillis(); } From 680adaa81aa64397832707d4d985b0347669813d Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Mon, 3 Oct 2016 12:23:56 -0400 Subject: [PATCH 10/11] Resolves #4, new functions to get/set individual date parts in the moment instance --- moment.cfc | 70 +++++++++++++++++++++++++++++ readme.md | 13 ++++++ tests/testbox/tests.cfc | 99 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) mode change 100644 => 100755 moment.cfc mode change 100644 => 100755 readme.md diff --git a/moment.cfc b/moment.cfc old mode 100644 new mode 100755 index 01eb957..9bd5f63 --- a/moment.cfc +++ b/moment.cfc @@ -284,6 +284,72 @@ component displayname="moment" { return getArbitraryTimeOffset( this.time, this.zone ); } + public function year( newYear = '' ){ + if ( newYear == '' ){ + return getDatePart( 'year' ); + }else{ + return init( + time: createDateTime( newYear, month(this.time), day(this.time), hour(this.time), minute(this.time), second(this.time) ) + ,zone: this.zone + ); + } + } + + public function month( newMonth = '' ){ + if ( newMonth == '' ){ + return getDatePart( 'month' ); + }else{ + return init( + time: createDateTime( year(this.time), newMonth, day(this.time), hour(this.time), minute(this.time), second(this.time) ) + ,zone: this.zone + ); + } + } + + public function day( newDay = '' ){ + if ( newDay == '' ){ + return getDatePart( 'day' ); + }else{ + return init( + time: createDateTime( year(this.time), month(this.time), newDay, hour(this.time), minute(this.time), second(this.time) ) + ,zone: this.zone + ); + } + } + + public function hour( newHour = '' ){ + if ( newHour == '' ){ + return getDatePart( 'hour' ); + }else{ + return init( + time: createDateTime( year(this.time), month(this.time), day(this.time), newHour, minute(this.time), second(this.time) ) + ,zone: this.zone + ); + } + } + + public function minute( newMinute = '' ){ + if ( newMinute == '' ){ + return getDatePart( 'minute' ); + }else{ + return init( + time: createDateTime( year(this.time), month(this.time), day(this.time), hour(this.time), newMinute, second(this.time) ) + ,zone: this.zone + ); + } + } + + public function second( newSecond = '' ){ + if ( newSecond == '' ){ + return getDatePart( 'second' ); + }else{ + return init( + time: createDateTime( year(this.time), month(this.time), day(this.time), hour(this.time), minute(this.time), newSecond ) + ,zone: this.zone + ); + } + } + //=========================================== //QUERY //=========================================== @@ -414,4 +480,8 @@ component displayname="moment" { return (targetOffset - startOffset) * 1000; } + private function getDatePart( datePart ){ + return val( format( canonicalizeDatePart( arguments.datePart ) ) ); + } + } diff --git a/readme.md b/readme.md old mode 100644 new mode 100755 index 23b0675..7464de2 --- a/readme.md +++ b/readme.md @@ -175,6 +175,19 @@ After all is said and done, sometimes you just need the raw datetime object back raw = new moment( '2008-11-27 13:47' ).getDateTime(); //=> {ts '2008-11-27 13:47:00'} +#### year, month, day, hour, minute, second + +Read or write just the year portion of the moment. When updating, returns a new moment instance. + + x = new moment(); + x.year(); + //=> returns the current year (numeric) + + x.year( 2000 ); + //=> returns a new moment with the date/time rewound to the same moment in the year 2000 + +The same pattern repeats for each of the following methods: `year()`, `month()`, `day()`, `hour()`, `minute()`, `second()`. Execute it with no arguments to get the current value, or execute it with an appropriate argument value to return a new moment maching the same date and time except for the specified date-part modification. + ## Time Zones In addition to all of the great date math you can do (with moment's better syntax), moment also has baked-in support for Time Zone functionality, using the robust underlying `java.util.TimeZone` class. diff --git a/tests/testbox/tests.cfc b/tests/testbox/tests.cfc index d87aadc..4fcc2a0 100644 --- a/tests/testbox/tests.cfc +++ b/tests/testbox/tests.cfc @@ -889,6 +889,105 @@ component extends="testbox.system.BaseSpec" { }); }); + describe("year()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + expect( d.year() ).toBe( 2015 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + var test = d.year( 2014 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2014 ); + expect( test.format('mm') ).toBe( 3 ); + expect( test.format('dd') ).toBe( 20 ); + }); + }); + + describe("month()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + expect( d.month() ).toBe( 3 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + var test = d.month( 5 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2015 ); + expect( test.format('mm') ).toBe( 5 ); + expect( test.format('dd') ).toBe( 20 ); + }); + }); + + describe("day()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + expect( d.day() ).toBe( 20 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 00:00:00', 'America/New_York'); + var test = d.day( 7 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2015 ); + expect( test.format('mm') ).toBe( 03 ); + expect( test.format('dd') ).toBe( 7 ); + }); + }); + + describe("hour()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 09:00:00', 'America/New_York'); + expect( d.hour() ).toBe( 9 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 09:10:11', 'America/New_York'); + var test = d.hour( 13 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2015 ); + expect( test.format('mm') ).toBe( 03 ); + expect( test.format('dd') ).toBe( 20 ); + expect( test.format('HH') ).toBe( 13 ); + expect( test.format('nn') ).toBe( 10 ); + expect( test.format('ss') ).toBe( 11 ); + }); + }); + + describe("minute()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 09:03:00', 'America/New_York'); + expect( d.minute() ).toBe( 3 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 09:10:11', 'America/New_York'); + var test = d.minute( 44 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2015 ); + expect( test.format('mm') ).toBe( 03 ); + expect( test.format('dd') ).toBe( 20 ); + expect( test.format('HH') ).toBe( 09 ); + expect( test.format('nn') ).toBe( 44 ); + expect( test.format('ss') ).toBe( 11 ); + }); + }); + + describe("second()", function(){ + it("returns the current value when argument is empty", function(){ + var d = moment('2015-03-20 09:00:59', 'America/New_York'); + expect( d.second() ).toBe( 59 ); + }); + it("returns an updated moment when argument is not empty", function(){ + var d = moment('2015-03-20 09:10:11', 'America/New_York'); + var test = d.second( 22 ); + expect( test ).toBeComponent(); + expect( test.format('yyyy') ).toBe( 2015 ); + expect( test.format('mm') ).toBe( 03 ); + expect( test.format('dd') ).toBe( 20 ); + expect( test.format('HH') ).toBe( 9 ); + expect( test.format('nn') ).toBe( 10 ); + expect( test.format('ss') ).toBe( 22 ); + }); + }); + }); describe("QUERY", function(){ From fee1001c27635f967f1061e5150db97d26349128 Mon Sep 17 00:00:00 2001 From: Arthur Sieler Date: Thu, 9 Jun 2016 18:38:21 -0400 Subject: [PATCH 11/11] added ability to accept epoch when moment is initialized --- moment.cfc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/moment.cfc b/moment.cfc index 9bd5f63..d4242ac 100755 --- a/moment.cfc +++ b/moment.cfc @@ -26,7 +26,11 @@ component displayname="moment" { -- for instance initialized to someTimeValue in someTZID TZ */ public function init( time = now(), zone = getSystemTZ() ) { - this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + if (isNumeric(time)) + this.time = epochToDate(arguments.time); + else + this.time = (time contains '{ts') ? time : parseDateTime( arguments.time ); + this.zone = zone; this.utc_conversion_offset = getTargetOffsetDiff( getSystemTZ(), zone, time ); this.utcTime = TZtoUTC( arguments.time, arguments.zone ); @@ -382,7 +386,17 @@ component displayname="moment" { //=========================================== //INTERNAL HELPERS //=========================================== + + private function epochToDate( epoch ){ + var d = ""; + if (isValid("integer",arguments.epoch)) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch*1000)); + else if (isNumeric(arguments.epoch) and val(arguments.epoch) gt 1000) + d = createObject("java","java.util.Date").init(javacast("long",arguments.epoch)); + return d; + } + private function getSystemTimeMS(){ return createObject('java', 'java.lang.System').currentTimeMillis(); }