Dealing with (birthday) dates and Timezone with Dojo - date

I have a simple widget that has:
<input class="input" id="${id}_dateOfBirth" name="dateOfBirth" data-dojo-type="dijit/form/DateTextBox" />
Note that it's a birthday. So, it's meant to stay the same, regardless of where you are when you are (timezone shouldn't happen). If you are born on the 10th of January at 3:00AM in England, and view your personal information from New York, you are meant to still see 10th of January, NOT the 9th!
I am in GMT+8 right now.
When I submit this form, this actually gets to the server when I put in 1/1/1970:
dateOfBirth: "1969-12-31T16:00:00.000Z"
Which is bad, because it's 8 hours short of the actual date.
Basically, I need a way for the DateTextBox to show the date as it came from the server, effectively ignoring the browser's timezone.

FWIW, here is my variant of UTCDateTextBox:
define([
"dojo/_base/declare",
"dijit/form/DateTextBox"
], function(declare, DateTextBox) {
function isValidDate(value) {
return value instanceof Date && isFinite(value.getTime());
}
function toUTCDate(value) {
if (isValidDate(value)) {
value = new Date(
Date.UTC(value.getFullYear(), value.getMonth(), value.getDate())
);
}
return value;
}
return declare(DateTextBox, {
_getValueAttr : function() {
return toUTCDate(this.inherited("_getValueAttr", arguments));
}
});
});
For my use case, I found that I didn't need to override _setValueAttr(). With the above implementation, when getUTCXXX(), toUTCString(), toISOString() or toJSON() are called on the date object returned from _getValueAttr(), then the correct UTC date with zeroed time elements is returned.
Hope this helps.

After much hacking and analysing Dojo's source code, I came up with this:
var UTCDateTextBox = declare( 'UTCDateTextBox', [ DateTextBox ], {
_getValueAttr: function(){
var ov = this.inherited(arguments);
if( ov ){
ov.setTime( ov.getTime() - ov.getTimezoneOffset() * 60 * 1000 );
}
return ov;
},
_setValueAttr: function( value, priorityChange, formattedValue){
var v = stamp.fromISOString( value );
if( v ){
v.setTime( v.getTime() + v.getTimezoneOffset() * 60 * 1000 );
value = v;
}
this.inherited(arguments);
}
});
Basically:
When the value is set, the timezone difference gets added. This means that if the server has 1979-12-25T00:00:00.000Z, rather than assigning Tue Dec 25 1979 08:00:00 GMT+0800 (WST), it will assign Tue Dec 25 1979 00:00:00 GMT+0800 (WST) . Basically, the date is converted locally to whatever it was in UTC.
When the value is parsed, it will be changed from Tue Dec 25 1979 00:00:00 GMT+0800 (WST) to Tue Dec 25 1979 08:00:00 GMT+0800 (WST)
The changed value is the one submitted to the server. So, it will be correct regardless of what timezone it will be edited at.
Since I only ever ever deal with dates, if the server has 1979-12-31T23:00:00Z (which is an error: for birthdays, the time is actually ignored and mustn't matter), this will happen:
When the value is set, ISO is 1979-12-31T23:00:00.000Z. So, Tue Jan 01 1980 07:00:00 GMT+0800 (WST) is changed into Mon Dec 31 1979 23:00:00 GMT+0800 (WST). This means that the right date is placed into the date textbox (31/12/1979).
When the value is parsed from the textbox, Mon Dec 31 1979 00:00:00 GMT+0800 (WST) becomes Mon Dec 31 1979 08:00:00 GMT+0800 (WST). So, the server will save 1979-12-31T00:00:00Z -- which is, again, the correct date!
If there are bettere solutions, please let me know. Frankly, I hope there are as this one feels like a bit of a cheat!

Related

Is there any formula that i can use to how to show up value (month) in between from start to end date in spreadsheet

Is there any formula that I can use to show up each month according to start & end date in spreadsheet.
Example:
Start Date:2022-07-22
End Date:2022-10-22
I expected formula to extract value something like this
Jul - Aug - Sep - Oct
I've tried formula
=IF(A2="","",IF(TEXT(B2,"MM")-TEXT(A2,"MM")>1,CONCATENATE(TEXT(A2,"MMM")&" - "&text(EDATE(A2,1),"MMM")&" - "&TEXT(B2,"MMM")),IF(TEXT(A2,"MMM")=TEXT(B2,"MMM"),TEXT(A2,"MMM"),CONCATENATE(TEXT(A2,"MMM")&" - "&TEXT(B2,"MMM"))))) but it only give me correct value if there is up to 3 month period between start & end date.
Here's a link to the sample spreadsheet
For single cell can try-
=JOIN("-",UNIQUE(INDEX(TEXT(SEQUENCE(B2-A2+1,1,A2),"mmm"))))
For spill array-
=BYROW(A2:INDEX(B2:B,MATCH(9^9,B2:B)),LAMBDA(x,JOIN("-",UNIQUE(INDEX(TEXT(SEQUENCE(INDEX(x,2)-INDEX(x,1)+1,1,INDEX(x,1)),"mmm"))))))
See your sheet.
Get the difference in dates in months using DATEDIF and get dates in each intervening month using EOMONTH+SEQUENCE and convert the end of month dates to TEXT:
Start Date
End Date
Months
2022-07-01
2022-10-30
Jul - Aug - Sep - Oct
2022-08-02
2022-08-31
Aug
2022-07-03
2022-11-01
Jul - Aug - Sep - Oct - Nov
Drag fill formula:
=ARRAYFORMULA(JOIN(" - ",TEXT(EOMONTH(A2,SEQUENCE(DATEDIF(A2,EOMONTH(B2,),"M")+1)-1),"mmm")))
Or as a self adjusting array formula:
=MAP(A2:INDEX(A:A,COUNTA(A:A)),LAMBDA(a, ARRAYFORMULA(JOIN(" - ",TEXT(EOMONTH(a,SEQUENCE(DATEDIF(a,EOMONTH(OFFSET(a,0,1),),"M")+1)-1),"mmm")))))
This should be faster and efficient than getting all the dates and filtering them out one by one, thereby reducing space and time complexity.
Use sequence(), edate() and join(), like this:
=arrayformula( map(
A2:A, B2:B,
lambda(
start, end,
if(
isdate(start) * isdate(end),
join(
" - ",
text(
edate(
start,
sequence(
12 * (year(end) - year(start)) + month(end) - month(start) + 1,
1, 0
)
),
"MMM"
)
),
iferror(1/0)
)
)
) )

parse javascript date to elixir format

I have some saved dates in JavaScript using new Date() that looks like:
"Sun Feb 24 2019 14:44:20 GMT+0200 (Eastern European Standard Time)"
I'm trying to parse these to Elixir DateTime; I didn't find anything in "timex" that can help and I already know that I can use DateTime.from_iso8601 but for dates saved using new Date().toISOString() but what i need is to parse the above string.
Thanks in advance
You can use elixir binary pattern matching to extract the date parts and parse using Timex's RFC1123 format. The RFC1123 is the format e.g Tue, 05 Mar 2013 23:25:19 +0200. Run h Timex.Format.DateTime.Formatters.Default in iex to see other formats.
iex> date_string = "Sun Feb 24 2019 14:44:20 GMT+0200 (Eastern European Standard Time)"
iex> <<day_name::binary-3,_,month_name::binary-3,_,day::binary-2,_,year::binary-4,_,time::binary-8,_::binary-4,offset::binary-5,_,rest::binary>> = date_string
iex> Timex.parse("#{day_name}, #{day} #{month_name} #{year} #{time} #{offset}", "{RFC1123}")
iex> {:ok, #DateTime<2019-02-24 14:44:20+02:00 +02 Etc/GMT-2>}
Pattern matching:
The binary-size are in byte sizes. 1 byte == 1 character. For instance to get
3-character day_name the size is 3. Underscores (_) is used to pattern match the spaces in the date format
Updated answer to use binary-size rather than bitstring-size for simplicity
I didn't find anything in "timex" that can help
The Timex Parsing docs say that you can use strftime sequences, e.g %H:%M:%S, for parsing. Here's a list of strftime characters and what they match.
Here's a format string that I think should work on javascript Dates:
def parse_js_date() do
Timex.parse!("Sun Feb 24 2019 14:44:20 GMT+0200 (Eastern European Standard Time)",
"%a %b %d %Y %H:%M:%S GMT%z (%Z)",
:strftime)
end
Unfortunately, %Z doesn't want to match the time zone name, which causes Timex.parse!() to spit out an error. It looks like %Z in Elixir only matches one word, e.g. a timezone abbreviation EET. Therefore, my simple, clean solution is spoiled.
What you can do is chop off the time zone name before parsing the date string:
def parse_js_date_string() do
[date_str|_tz_name] = String.split(
"Sun Feb 24 2019 14:44:20 GMT+0200 (Eastern European Standard Time)",
" (",
parts: 2
)
Timex.parse!(date_str,
"%a %b %d %Y %H:%M:%S GMT%z",
:strftime)
end
In iex:
~/elixir_programs/my$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Compiling 1 file (.ex)
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> My.parse_js_date_string()
#DateTime<2019-02-24 14:44:20+02:00 +02 Etc/GMT-2>
iex(2)>

Change date format 08 / 03 / 2017 to 08 March 2017

I'm trying to change date format from 08/03/2017
08 day
03 Month
2017 year
I I'm using
date("d F Y", strtotime($date));
the problem is that I Get 03 August 2017 instead of 08 March 2017
PS : I can't use any other then
dd/mm/yyyy
Try this
$date = DateTime::createFromFormat('d/m/Y', "08/03/2017");
echo $date->format('d F Y');
You can check it to http://php.net/manual/en/datetime.createfromformat.php
After Some researchs I found a solution
str_replace(' / ', '-',$date)
/*
You got August because you provide wrong format to this function. Function accept m/d/y and you provide d/m/y. you can try with this format m/d/y
or
you can try this with DateTime object.
*/
$date = "08/03/2017";
$dateObject = DateTime::createFromFormat('d/m/Y', $date);
echo $dateObject->format('d M Y');

Between Dates using Waterline ORM SailsJS

Goal: Return a list of items that were created between two dates.
According to this issue https://github.com/balderdashy/waterline/issues/110 there is no between function just yet. However the work around is the following:
User.find({
date: { '>': new Date('2/4/2014'), '<': new Date('2/7/2014') }
}).exec(/* ... */);
To be more exact, we don't want the hard coded dates above so we read in the input from a form submission like so:
start = new Date(req.param('yearStart') + '/' + req.param('monthStart') + '/' + req.param('dayStart'));
end = new Date(req.param('yearEnd') + '/' + req.param('monthEnd') + '/' + req.param('dayEnd'));
Printing start and end to console shows me this (different timezones for some reason)?
from: Sat Mar 01 2014 00:00:00 GMT-0500 (EST)
to: Sat Apr 30 2016 00:00:00 GMT-0400 (EDT)
However my view returns nothing every time.
While writing this question I realized the issue was that I had date instead of createdAt in my filter.
So the following works:
User.find({
createdAt: { '>': start, '<': end }
}).exec(/* ... */);
If you are wondering how to use the API blueprint query, you will need to use the toISOString() method of the Date object. For example :
http://localhost:1337/:model/?where={date: {'<=', date.toISOString()}}

Automatically put working week

Right now i am working on a weekly basis gathering the data and put the week and month manually. For example: The working week for today this week is June 23 thru June 29. and the month is June 2014.
I want to gather the YTD data and based on the date put the Week and Month automatically
For example:
Referral Request Date Week Month
1/3/2014 0:00 December 30 thru January 05, 2014 January 2014
1/3/2014 11:10 December 30 thru January 05, 2014 January 2014
12/31/2013 0:00 December 30 thru January 05, 2014 December 2013
6/18/2014 0:00 June 16 thru June 22, 2014 June 2014
6/20/2014 9:51 June 16 thru June 22, 2014 June 2014
4/28/2014 16:34 April 28 thru May 04, 2014 April 2014
5/1/2014 15:22 April 28 thru May 04, 2014 May 2014
The working week will begin each monday and finished on Sunday.
It can be do automatically?? The file have thousand of lines...
Here you are:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use DateTime;
use DateTime::Format::Strptime;
my #datetimes = (
'1/3/2014 0:00',
'1/3/2014 11:10',
'12/31/2013 0:00',
'6/18/2014 0:00',
'6/20/2014 9:51',
'4/28/2014 16:34',
'5/1/2014 15:22',
);
for my $datetime_str (#datetimes) {
my $strp = 'DateTime::Format::Strptime'->new( pattern => '%m/%d/%Y %H:%M' );
my $dt = $strp->parse_datetime($datetime_str);
my $month_year_strp = 'DateTime::Format::Strptime'->new( pattern => '%B %Y' );
my $month_year = $month_year_strp->format_datetime($dt);
my $desired_dow = 1; # Monday
$dt->subtract(days => ($dt->day_of_week - $desired_dow) % 7);
my $month_day_strp = 'DateTime::Format::Strptime'->new( pattern => '%B %d' );
my $monday = $month_day_strp->format_datetime($dt);
$dt->add(days => 6);
my $sunday = $month_day_strp->format_datetime($dt);
say "$datetime_str, $monday thru $sunday, $month_year";
}
Next time help someone else (in case this is what you're after -- I am not sure if I got your question). :-) I used the link posted by #scragar in comments.