Date formatting using moment - momentjs

I was playing with moment library in node and was trying to format dates:
moment().tz(timezone).format('dddd')
This formatting gives me the current day of the week like 'Tuesday'
Now, I want to format like: 'Tuesday May 2, 2017'
What will be the best way to format it this way using moment?

You can simply use moment format(), in your case you have to use 'dddd MMMM D, YYYY' where:
dddd stands for the day of the week name
MMMM stands for month's name
D stands for the day of the month
YYYY stands for the four digit year
Here a working sample:
var timezone = 'Europe/Rome';
console.log(moment().tz(timezone).format('dddd MMMM D, YYYY'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.13/moment-timezone-with-data-2012-2022.min.js"></script>

Related

Scanning A Text String Then Month Year Format with Month End Date

I searched on Stackoverflow and was able to write this formula by reading a cell's Month Year Date Time to give me this (Column A from reading Column H):
Column A Cell A2 (A2 indicates 4/1/2021) =DATE(YEAR(H2),MONTH(H2)+1,1) which reads this 3/30/2021 5:09:55 PM.
Then I wrote a formula in Column I for giving me the Month Year format for I2 reading from A2:
=TEXT(A2,"mmmm yyyy") which is April 2021 then I copy and paste as value into Column B (B2 as April 2021)
Is there an IF statement or a formula I can write when scanning say Column I (I2 = "April 2021) to give me the Month~MonthEnd-Date~Year format? ie "April 2021" to "April 30th 2021"?
This might require a new thread but how do I "turn-on" the auto feature whenever I add a new row to keep the new rows as part of a Table?
If you are just looking for the start of the following month in column A, you formula works fine. An alternative formula for column A could be:
=EOMONTH(I2,0)+1
As an alternative to converting the date to a text value, you can format the cell to display date in the same format. The advantage to this is the cell is still an excel date that formulas can easily work with.
Again to get the last day of the month use EOMONTH formula. If you want to keep your text method going, use the following formula:
=TEXT(EOMONTH(A2,0),"mmmm dd yyyy")
Alternatively if you format the cell appropriately, you can just use:
=EOMONTH(A2,0)
Note if you really need the st for days ending in 1 and nd for days end 2, etc, it gets more complicated. I am assuming that they are not really needed.

Get date-time from past date-time + duration

The service returns a past date-time in ISO 8601 format like 2018-03-23T08:00:00Z and a duration in PnYnMnDTnHnMnS format like: PT3H. From those 2 values I need to calculate the date-time of the end of the duration. So in my case it would be 2018-03-23T11:00:00Z.
I'm using moment.js for this. The problem is, when I'm tring to get the duration end date-time it returns a human readable string like in xy hours.
The problems I'm facing:
It returns wrong duration. If I have PT3H it should return in 3 hours but it returns in 9 hours instead.
The end date-time should be in milliseconds, currently its in "human readable form"
My code:
let dur = moment.duration("PT3H");
let myDate = moment("2018-03-23T08:00:00Z");
myDate.from(dur); // It returns "in 9 hours"
JsBin
You can add your duration to your date using add(Duration) and then use from.
Note that from accepts: Moment|String|Number|Date|Array while, in your code, you are passing a duration (dur).
You can use diff to get the difference in milliseconds.
If you want to get Unix timestamp of a moment object you can use valueOf().
Here a live sample:
let dur = moment.duration("PT3H");
let myDate = moment("2018-03-23T08:00:00Z");
let m2 = myDate.clone().add(dur);
console.log(m2.from(myDate));
let diff = m2.diff(myDate);
console.log(diff);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script>

How to format date according to local formatting wit MomentJS?

With MomentJS how can I format a date according to the local datetime format?
Currently I display the time as follows:
var zone = moment.tz.guess();
var usertime = moment.tz(ucttime, zone).format('LLL');
But when changing the zone to Asia/Seoul I still get the American formatting using AM/PM:
January 30, 2018 11:37 AM
Basically I'm looking for JavaScript's toLocaleDateString() equivalent.
I've tried the following, but the output is wrong:
var usertime = moment.tz(ucttime, zone).toDate().toLocaleString();
Which outputs (for Asia/Seoul):
1/29/2018, 6:32:37 PM
While it should be:
2018. 1. 29. 오후 6:32
Update:
This displays the correct formatting, but breaks the timezone ajustment:
usertime = moment.tz(ucttime, zone).toDate().toLocaleString(navigator.language);
Given that you have referenced moment.js, locale/ko.js, moment-timezone-with-data.js, you can use this format:
moment.tz(moment(), moment.tz.guess()).locale('ko').format('YYYY. M. DD. a H:mm')

as.Date produces unexpected result in a sequence of week-based dates

I am working on the transformation of week based dates to month based dates.
When checking my work, I found the following problem in my data which is the result of a simple call to as.Date()
as.Date("2016-50-4", format = "%Y-%U-%u")
as.Date("2016-50-5", format = "%Y-%U-%u")
as.Date("2016-50-6", format = "%Y-%U-%u")
as.Date("2016-50-7", format = "%Y-%U-%u") # this is the problem
The previous code yields correct date for the first 3 lines:
"2016-12-15"
"2016-12-16"
"2016-12-17"
The last line of code however, goes back 1 week:
"2016-12-11"
Can anybody explain what is happening here?
Working with week of the year can become very tricky. You may try to convert the dates using the ISOweek package:
# create date strings in the format given by the OP
wd <- c("2016-50-4","2016-50-5","2016-50-6","2016-50-7", "2016-51-1", "2016-52-7")
# convert to "normal" dates
ISOweek::ISOweek2date(stringr::str_replace(wd, "-", "-W"))
The result
#[1] "2016-12-15" "2016-12-16" "2016-12-17" "2016-12-18" "2016-12-19" "2017-01-01"
is of class Date.
Note that the ISO week-based date format is yyyy-Www-d with a capital W preceeding the week number. This is required to distinguish it from the standard month-based date format yyyy-mm-dd.
So, in order to convert the date strings provided by the OP using ISOweek2date() it is necessary to insert a W after the first hyphen which is accomplished by replacing the first - by -W in each string.
Also note that ISO weeks start on Monday and the days of the week are numbered 1 to 7. The year which belongs to an ISO week may differ from the calendar year. This can be seen from the sample dates above where the week-based date 2016-W52-7 is converted to 2017-01-01.
About the ISOweek package
Back in 2011, the %G, %g, %u, and %V format specifications weren't available to strptime() in the Windows version of R. This was annoying as I had to prepare weekly reports including week-on-week comparisons. I spent hours to find a solution for dealing with ISO weeks, ISO weekdays, and ISO years. Finally, I ended up creating the ISOweek package and publishing it on CRAN. Today, the package still has its merits as the aforementioned formats are ignored on input (see ?strptime for details).
As #lmo said in the comments, %u stands for the weekdays as a decimal number (1–7, with Monday as 1) and %U stands for the week of the year as decimal number (00–53) using Sunday as the first day. Thus, as.Date("2016-50-7", format = "%Y-%U-%u") will result in "2016-12-11".
However, if that should give "2016-12-18", then you should use a week format that has also Monday as starting day. According to the documentation of ?strptime you would expect that the format "%Y-%V-%u" thus gives the correct output, where %V stands for the week of the year as decimal number (01–53) with monday as the first day.
Unfortunately, it doesn't:
> as.Date("2016-50-7", format = "%Y-%V-%u")
[1] "2016-01-18"
However, at the end of the explanation of %V it sais "Accepted but ignored on input" meaning that it won't work.
You can circumvent this behavior as follows to get the correct dates:
# create a vector of dates
d <- c("2016-50-4","2016-50-5","2016-50-6","2016-50-7", "2016-51-1")
# convert to the correct dates
as.Date(paste0(substr(d,1,8), as.integer(substring(d,9))-1), "%Y-%U-%w") + 1
which gives:
[1] "2016-12-15" "2016-12-16" "2016-12-17" "2016-12-18" "2016-12-19"
The issue is because for %u, 1 is Monday and 7 is Sunday of the week. The problem is further complicated by the fact that %U assumes week begins on Sunday.
For the given input and expected behavior of format = "%Y-%U-%u", the output of line 4 is consistent with the output of previous 3 lines.
That is, if you want to use format = "%Y-%U-%u", you should pre-process your input. In this case, the fourth line would have to be as.Date("2016-51-7", format = "%Y-%U-%u") as revealed by
format(as.Date("2016-12-18"), "%Y-%U-%u")
# "2016-51-7"
Instead, you are currently passing "2016-50-7".
Better way of doing it might be to use the approach suggested in Uwe Block's answer. Since you are happy with "2016-50-4" being transformed to "2016-12-15", I suspect in your raw data, Monday is counted as 1 too. You could also create a custom function that changes the value of %U to count the week number as if week begins on Monday so that the output is as you expected.
#Function to change value of %U so that the week begins on Monday
pre_process = function(x, delim = "-"){
y = unlist(strsplit(x,delim))
# If the last day of the year is 7 (Sunday for %u),
# add 1 to the week to make it the week 00 of the next year
# I think there might be a better solution for this
if (y[2] == "53" & y[3] == "7"){
x = paste(as.integer(y[1])+1,"00",y[3],sep = delim)
} else if (y[3] == "7"){
# If the day is 7 (Sunday for %u), add 1 to the week
x = paste(y[1],as.integer(y[2])+1,y[3],sep = delim)
}
return(x)
}
And usage would be
as.Date(pre_process("2016-50-7"), format = "%Y-%U-%u")
# [1] "2016-12-18"
I'm not quite sure how to handle when the year ends on a Sunday.

Bucketing data into weekly, bi-weekly, monthly and quarterly data in R

I have a data frame with two columns. Date, Gender
I want to change the Date column to the start of the week for that observation. For example if Jun-28-2011 is a Tuesday, I'd like to change it to Jun-27-2011. Basically I want to re-label Date fields such that two data points that are in the same week have the same Date.
I also want to be able to do it by-weekly, or monthly and specially quarterly.
Update:
Let's use this as a dataset.
datset <- data.frame(date = as.Date("2011-06-28")+c(1:100))
One slick way to do this that I just learned recently is to use the lubridate package:
library(lubridate)
datset <- data.frame(date = as.Date("2011-06-28")+c(1:100))
#Add 1, since floor_date appears to round down to Sundays
floor_date(datset$date,"week") + 1
I'm not sure about how to do bi-weekly binning, but monthly and quarterly are easily handled with the respective base functions:
quarters(datset$date)
months(datset$date)
EDIT: Interestingly, floor_date from lubridate does not appear to be able to round down to the nearest quarter, but the function of the same name in ggplot2 does.
Look at ?strftime. In particular, the following formats:
%b: Abbreviated month name in the
current locale. (Also matches full
name on input.)
%B: Full month name
in the current locale. (Also matches
abbreviated name on input.)
%m: Month as decimal number (01–12).
%W: Week of the year as decimal number
(00–53) using Monday as the first day
of week (and typically with the first
Monday of the year as day 1 of week
1). The UK convention.
eg:
> strftime("2011-07-28","Month: %B, Week: %W")
[1] "Month: July, Week: 30"
> paste("Quarter:",ceiling(as.integer(strftime("2011-07-28","%m"))/3))
[1] "Quarter: 3"

Resources