I'm looking to map a date/week to the Week number of the year.
I've thought about subtracting the start of the year, and dividing by 7 - however it might not line up correctly.
e.g.
2020.01.02 -> Week 1
2020.01.06 -> Week 2
I would suggest to use following function:
weekOfYear: {1+floor (x-`week$"d"$12 xbar"m"$x)%7}
This function
Finds the first Monday before or on 1st Jan. E.g. {(`week$"d"$12 xbar"m"$x)}2020.01.01 returns 2019.12.30
Then finds difference in days between x and the first Monday
Divides difference by 7 and adds 1, which returns result you are looking for
For example
weekOfYear 2019.12.31 2020.01.01 2020.01.02 2020.01.05 2020.01.06 2020.01.07
returns
53 1 1 1 2 2
Just to build on Antons great answer, you could also use the div function instead of flooring it, which would look something like
{1 + (x - `week $ `date $ 12 xbar `month $ x) div 7}
As per MDN
"Date objects are based on a time value that is the number of milliseconds since 1 January, 1970 UTC."
Then why does it accept negative values ?
Even if it did shouldn't negative value mean values before Jan 1, 1970 ?
new Date('0000', '00', '-1'); // "1899-12-30T05:00:00.000Z"
new Date('0000', '00', '00'); // "1899-12-31T05:00:00.000Z"
new Date('-9999', '99', '99'); // "-009991-07-08T04:00:00.000Z"
What is happening ?
Update
For some positive values , the year begins from 1900
new Date(100); // "1970-01-01T00:00:00.100Z" // it says 100Z
new Date(0100); // "1970-01-01T00:00:00.064Z" // it says 64Z
new Date("0006","06","06"); // "1906-07-06T04:00:00.000Z"
Also note that, in the last one, the date is shown as 4 which is wrong.
I suspect this is some sort of Y2K bug ?!!
This is hard and inconsistent, yes. The JavaScript Date object was based on the one in Java 1.0, which is so bad that Java redesigned a whole new package.
JavaScript is not so lucky.
Date is "based on" unix epoch because of how it is defined. It's internal details.
1st Jan 1970 is the actual time of this baseline.
since is the direction of the timestamp value: forward for +ve, backward for -ve.
Externally, the Date constructor has several different usages, based on parameters:
Zero parameters = current time
new Date() // Current datetime. Every tutorial should teach this.
The time is absolute, but 'displayed' timezone may be UTC or local.
For simplicity, this answer will use only UTC. Keep timezone in mind when you test.
One numeric parameter = timestamp # 1970
new Date(0) // 0ms from 1970-01-01T00:00:00Z.
new Date(100) // 100ms from 1970 baseline.
new Date(-10) // -10ms from 1970 baseline.
One string parameter = iso date string
new Date('000') // Short years are invalid, need at least four digits.
new Date('0000') // 0000-01-01. Valid because there are four digits.
new Date('1900') // 1900-01-01.
new Date('1900-01-01') // Same as above.
new Date('1900-01-01T00:00:00') // Same as above.
new Date('-000001') // 2 BC, see below. Yes you need all those zeros.
Two or more parameters = year, month, and so on # 1900 or 0000
new Date(0,0) // 1900-01-01T00:00:00Z.
new Date(0,0,1) // Same as above. Date is 1 based.
new Date(0,0,0) // 1 day before 1900 = 1899-12-31.
new Date(0,-1) // 1 month before 1900 = 1899-12-01.
new Date(0,-1,0) // 1 month and 1 day before 1900 = 1899-11-30.
new Date(0,-1,-1) // 1 month and *2* days before 1900 = 1899-11-29.
new Date('0','1') // 1900-02-01. Two+ params always cast to year and month.
new Date(100,0) // 0100-01-01. Year > 99 use year 0 not 1900.
new Date(1900,0) // 1900-01-01. Same as new Date(0,0). So intuitive!
Negative year = BC
new Date(-1,0) // 1 year before 0000-01-01 = 1 year before 1 BC = 2 BC.
new Date(-1,0,-1) // 2 days before 2 BC. Fun, yes? I'll leave this as an exercise.
There is no 0 AC. There is 1 AC and the year before it is 1 BC. Year 0 is 1 BC by convention.
2 BC is displayed as year "-000001".
The extra zeros are required because it is outside normal range (0000 to 9999).
If you new Date(12345,0) you will get "+012345-01-01", too.
Of course, the Gregorian calendar, adopted as late as 1923 in Europe, will cease to be meaningful long before we reach BC.
In fact, scholars accept that Jesus wasn't born in 1 BC.
But with the stars and the land moving at this scale, calendar is the least of your worries.
The remaining given code are just variations of these cases. For example:
new Date(0100) // One number = epoch. 0100 (octal) = 64ms since 1970
new Date('0100') // One string = iso = 0100-01-01.
new Date(-9999, 99, 99) // 9999 years before BC 1 and then add 99 months and 98 days
Hope you had some fun time. Please don't forget to vote up. :)
To stay sane, keep all dates in ISO 8601 and use the string constructor.
And if you need to handle timezone, keep all datetimes in UTC.
Well, firstly, you're passing in string instead of an integer, so that might have something to do with your issues here.
Check this out, it explains negative dates quite nicely, and there is an explanation for your exact example.
Then why does it accept negative values ?
You are confusing the description of how the data is stored internally with the arguments that the constructor function takes.
Even if it did shouldn't negative value mean values before Jan 1, 1970 ?
No, for the above reason. Nothing stops the year, month or day from being negative. You just end up adding a negative number to something.
Also note that, in the last one, the date is shown as 4 which is wrong.
Numbers which start with a 0 are expressed in octal, not decimal. 0100 === 64.
Please have a look at the documentation
Year: Values from 0 to 99 map to the years 1900 to 1999
1970 with appropriate timezone: new Date(0); // int MS since 1970
1900 (or 1899 with applied timezone): new Date(0,0) or new Date(0,0,1) - date is 1 based, month and year are 0 based
1899: new Date(0,0,-1)
How would you parse a date string in format "dd/MM/yyyy" using q kdb?
It is possible when the month argument is first "MM/dd/yyyy" as follows:
"D"$"1/20/2014"
2014-01-20d
However if day is first "dd/MM/yyyy"
"D"$"20/1/2014"
0Nd
KDB supports parsing of different datetime formats. Check details here:
https://code.kx.com/q/ref/casting/#tok
For your case you need to set 'z' option which specifies the format for date parsing.
0 is "mm/dd/yyyy" and 1 is "dd/mm/yyyy".
Details: https://code.kx.com/q/ref/syscmds/#z-date-parsing
This is how you do it for your example:
q) \z 1
q) "D"$"20/1/2014"
q) 2014.01.20
If you want to avoid changing system variables and have greater control over all possible date formats you can always write a custom date parser such as this:
f:{"D"$raze"0"^neg[4 2 2]$(y vs z)iasc`YYYY`MM`DD?x}
Which takes 3 parameters; date format expected, delimiter and date string. To handle your example it would be set up as follows:
q)f[`MM`DD`YYYY;"/";"1/20/2014"]
2014.01.20
It can also handle more unconventional date formats:
q)f[`MM`YYYY`DD;"p";"1p2014p20"]
2014.01.20
Obviously the above is overkill compared to inbuilt date parsing for your example but it does give a greater degree of flexibility.
Note that you do not have to pad with zeroes (tested with 3.3):
q)"." sv ("/" vs "1/20/2014") 2 0 1
"2014.1.20"
q)"D"$ "." sv ("/" vs "1/20/2014") 2 0 1
2014.01.20
In a function:
q)f:{"D"$"."sv("/"vs x)2 0 1}
q)f "1/20/2014"
2014.01.20
If you want a function that can handle both lists and individual dates:
q)g:{"D"$$[10=type x;"."sv("/"vs x)2 0 1;"."sv/:("/"vs/:x)[;2 0 1]]}
q)g "7/20/2014"
2014.07.20
q)g ("1/20/2014";"7/20/2014";"03/20/2014")
2014.01.20 2014.07.20 2014.03.20
... which is a little better than using each:
q)\ts:100000 g ("1/20/2014";"7/20/2014";"03/20/2014")
308 1168
q)\ts:100000 f each ("1/20/2014";"7/20/2014";"03/20/2014")
327 1312
... and quicker than padding/razing:
q)h:{"D"$raze"0"^neg[4 2 2]$(y vs z)iasc`YYYY`MM`DD?x}[`MM`DD`YYYY;"/";]
q)\ts:100000 h each ("1/20/2014";"7/20/2014";"03/20/2014")
615 1312
I'm using Phoenix and Ecto. I need to check if a difference between "now()" and a certain date less than 3 days. Exactly I'm trying this:
{diff_days, {_, _, _}} = Ecto.DateTime.to_erl(my_user.signed_up_at) |> :calendar.time_difference(:calendar.universal_time)
if diff_days <= 3 do
# good to go
# ....
end
However, this won't for a date older than 3 days and 1 minute, right?
What's the univeral way to check if it's not more but 3 days or 72 hours?
In my database signed_up_at is of type timestamp without timezone
Use DateTime.diff/3:
three_days_in_seconds = 3 * 24 * 60 * 60
case DateTime.diff(DateTime.utc_now, my_user.signed_up_at, :second) do
good when good < three_days_in_seconds ->
# good to go
_ ->
# skip
end
Please note, that :second is a default value for the third argument in a call to DateTime.diff/3 and might be omitted.
I have daily data for a year:
25-Apr-17 45
26-Apr-17 50
27-Apr-17 53
28-Apr-17 47
29-Apr-17 34
30-Apr-17 66
01-May-17 10
02-May-17 42
03-May-17 22
04-May-17 65
05-May-17 76
06-May-17 35
I would like to sum the value, at the month of given date, but prior of the given date ie:
month sum as of date 03-May-17;
I would need to get 10+42+22 = 72 only.
While 04-May-17 value onwards should not be included in sum.
I have tried with sumproduct, sumif but none seems to match this requirement.
Assuming you want this in excel or google sheets.
If you put your dates in col A, values in col B and your criteria date in E1.
Put this formula in another cell (not in col A or B)
=arrayformula(SUM(IF(DAY(A:A)<=DAY($E$1),IF(MONTH(A:A)=MONTH($E$1),B:B,0),0)))
Oddly enough I couldn't do =IF(AND([range of values and compare],[range of values and compare]))
Which would be cleaner but it seemed to evaluate as false