Extract day, month, year from a YYYY-DD-MM string in Javascript - javascript

I am finding the best solution for extracting day, month, year from string with YYYY-DD-MM in Javascript:
Extract from:
2019-25-01
To object:
{ day: 25, month: 01, year: 2019 }
What is the best way to do it. Thank in advance!

You could split, destructure and return a new object.
const getDate = string => (([year, day, month]) => ({ day, month, year }))(string.split('-'));
console.log(getDate('2019-25-01'));

I'd use a regular expression to match each number sequence, map the array of matched strings to numbers, destructure into variables, then create an object from it:
const [year, day, month] = '2019-25-01'
.match(/\d+/g)
.map(Number);
const obj = { day, month, year };
console.log(obj);
Note that numbers cannot have leading zeros. If you want the month to have a leading zero, use a string instead (just remove the .map(Number)).

This is a pretty short and fast solution that will only work for that format and in ES6
function getJsonDate(text) {
var {0: year, 1: day, 2: month } = text.split("-");
return { day, month, year};
}
console.log(getJsonDate("2019-25-1"));
If you need the fields to be numbers then you can add a map, like so:
function toNumber(text) {
text = text - 0;
return isNaN(text) ? 0 : text;
}
function getJsonDate(text) {
var {0: year, 1: day, 2: month } = text.split("-").map(toNumber);
return { day, month, year};
}
console.log(getJsonDate("2019-25-1"));

You can split()to do it
var value = "2019-25-01";
var year = value.substring(0,4);
var day = value.substring(5,7);
var month = value.substring(8,10);
var str = "{day:" + day + ",month:" + month + ",year:" + year + "}";
console.log(str);

Use .split().
let date = "2019-25-01"
let dateArr = date.split('-')
let obj = {
day: dateArr[1],
month: dateArr[2],
year: dateArr[0]
}
console.log(obj)

For JSON like structure
d="2019-25-01";
x=d.split("-");
json="{ day: "+x[1]+", month: "+x[2]+", year: "+x[0]+" }";
>>"{ day: 25, month: 01, year: 2019 }"

Here you have one approach that don't need to do the mapping str -> array -> object, it will convert the string directly to object and can be used also for a more generalized date with time. It is based on the replacement function that can be used on String::replace()
const dateStr1 = "2019-25-01";
const dateMap1 = ["year", "day", "month"];
const dateStr2 = "2019-25-01 17:07:56";
const dateMap2 = ["year", "day", "month", "hour", "minute", "second"];
const splitDate = (str, map) =>
{
let obj = {}, i = 0;
str.replace(/\d+/g, (match) => obj[[map[i++] || i - 1]] = match);
return obj;
}
console.log(splitDate(dateStr1, dateMap1));
console.log(splitDate(dateStr2, dateMap2));
Another way that is strictly related to your date format could be next one:
const strDate = "2019-25-01";
const splitDate = (str) =>
{
let [date, year, day, month] = str.match(/(\d+)-(\d+)-(\d+)/);
return {year, month, day};
}
console.log(splitDate(strDate));

Related

Same date format between MongoDB and JS but they are not equal?

I'm trying to do an action when the date today (via Node.js) and the date value (via MongoDB) is the same. However, I'm not receiving any output from my for loop indicating that there's no match.
Here's how I get the date today (date output is 2023-01-19T00:00:00.000Z):
const d = new Date(new Date().toLocaleString("en-US", { timeZone: "Asia/Hong_Kong" }));
const day = d.getDate();
const month = d.getMonth() + 1;
const year = "2023"; //this is a dummy variable since year is required for Date().
const date = new Date(year + "-" + month + "-" + day);
console.log(date);
Here's the users document from MongoDB:
name: "Angelo"
birthday: 2023-01-11T00:00:00.000+00:00 //Date data type
name: "Josh"
birthday: 2023-01-19T00:00:00.000+00:00 //Date data type
Here's the for loop that should trigger success when there's a match, but there's no output. This is my problem.
let users = [];
db.collection("users").find({})
.forEach((user) => { users.push(user) })
.then(() => {
for (i = 0; i < users.length; i++) {
if(users[i].birthday == date) {
console.log("Success"); //no output on console
}
}
})
Checking users[i].birthday in console shows:
2023-01-19T00:00:00.000Z (Shouldn't this be a match of today's date?)
2023-01-11T00:00:00.000Z
MongoDB Date objects store values in UTC. In your example you create a date object in the local timezone, so your dates will not match.
You can create a UTC zero date using the Date.UTC() static method, where zero date means a date with zero for the hours, minutes, and seconds. Here is an example that simulates your users array from MongoDB, assuming that the birthdays are all UTC zero dates. You can't compare the date objects directly, because two date objects that have the same date have different object addresses. Therefore you need to compare the value of the date objects (.valueOf()), or a string representation (.toISOString()).
function getUtcZeroDate(str) {
if(str) {
return new Date(str + 'T00:00:00.000Z');
} else {
let date = new Date();
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
}
}
const users = [
{name: 'Angelo', birthday: getUtcZeroDate('2023-01-11') },
{name: 'Josh', birthday: getUtcZeroDate() }, // today
]
const todayUtcZeroDate = getUtcZeroDate();
console.log("Today's UTC zero date:", todayUtcZeroDate.toISOString());
users.forEach(doc => {
const match = (todayUtcZeroDate.valueOf() == doc.birthday.valueOf()) ? 'match' : 'no match';
console.log(doc.name + ', born ' + doc.birthday.toISOString(), '=>', match);
});
Output at the time of writing:
Today's UTC zero date: 2023-01-18T00:00:00.000Z
Angelo, born 2023-01-11T00:00:00.000Z => no match
Josh, born 2023-01-18T00:00:00.000Z => match
A simple way to compare dates is to use setHours(0,0,0) for both birthday date and date like below:
const d = new Date(new Date().toLocaleString("en-US", { timeZone: "Asia/Hong_Kong" }));
const day = d.getDate();
const month = d.getMonth() + 1;
const year = "2023"; //this is a dummy variable since year is required for Date().
let date = new Date(year + "-" + month + "-" + day);
date=date.setHours(0,0,0)
for fetching date and comparing from db:
let users = [];
db.collection("users").find({})
.forEach((user) => { users.push(user) })
.then(() => {
for (i = 0; i < users.length; i++) {
users[i].birthday=new Date(users[i].birthday).setHours(0,0,0)
if(users[i].birthday == date) {
console.log("Success"); // output on console
}
}
})
Try it you will get output.
I suggest considering using moment.js for this.
You'll be also need moment-timezone.js add-on to use timezones.
I recommend moment.js because with it, the code becomes more readable.
moment.tz.setDefault("Asia/Hong_Kong");
const users = [{
name: "Angelo",
birthday: new Date('2023-01-11T00:00:00.000+00:00'),
},
{
name: "Josh",
birthday: new Date('2023-01-19T00:00:00.000+00:00'),
},
];
const today = moment();
for (i = 0; i < users.length; i++) {
const user = users[i];
if ( today.isSame(user.birthday, 'date')) {
console.log("Success", users[i]);
}
}
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
This is really just a date formatting issue.
If you want to get the date in a particular location, you can use the Intl.DateTimeFormat constructor but get the parts as separate values rather than a timestamp that then must be parsed by the built–in parser. That's a flawed methodology because the built–in parser isn't required to correctly parse such input (same with toLocaleString).
So to get the current date in a particular location and then built a timestamp that is 0hrs UTC:
// Return the date at loc for the provided date as
// a Date set to year, month, day as UTC values.
function toUTCDateFromLoc(loc, date = new Date()) {
let f = new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
timeZone: loc
});
let {year, month, day} = f.formatToParts(date)
.reduce((acc, part) => {
acc[part.type] = part.value;
return acc;
}, Object.create(null));
return new Date(Date.UTC(year, month - 1, day));
}
// Kirimati and Midway should always be at least 1 day different
['Pacific/Kiritimati', // +14
'Asia/Hong_Kong', // +8
'America/Dominica', // -4
'Pacific/Midway', // -11
].forEach(loc => console.log(
`${loc.padEnd(18, ' ')}: ${toUTCDateFromLoc(loc).toISOString()}`
));

convert string to time javascript in order to have ability to sort it

I need to convert string of format "14.12.22 15:17" to date in order to sort it by seconds. thank you in advance
const toTimestamp = (strDate) => {
const parsedDate = strDate.split(".");
const b = parsedDate[2].split(" ");
const string = `20${b[0]}-${parsedDate[0]}-${parsedDate[1]}T${b[1]}:00`;
const date = new Date(string).getTime();
console.log(string);
return date;
};
toTimestamp('4.12.22 15:17');
You want to use Date.parse() after converting the string to ISO 8601 format:
const datestrings = ["14.12.22 15:17", "14.12.22 15:16", "12.12.22 22:22"]
const toTimestamp = (strDate) => {
const parts = strDate.split(" ")
const d = parts[0].split(".");
const t = parts[1]
const string = `20${d[2]}-${d[1]}-${d[0]}T${t}`;
const date = Date.parse(string);
console.log(string, date);
return date;
}
const dateTimes = []
datestrings.forEach(d => dateTimes.push(toTimestamp(d)))
dateTimes.sort()
console.log(dateTimes)
var t = "14.12.22 15:17"
var ts = t.split(" ");
var tss = ts[0].split(".")
var tsss = []
tsss.push(tss[1] + ".")
tsss.push(tss[0] + ".")
tsss.push(tss[2] + " ")
tsss.push(ts[1])
tsss.join();
var d = new Date(tsss);
console.log(d.getTime()/1000);
You can use third-party libraries for parsing the date, e.g., moment.js is one of the famous ones.
Your code can simplified as
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script>
const momentDate = moment('14.12.22 15:17', 'YY.MM.DD HH:mm');
console.log(momentDate.toDate());
</script>
</body>
</html>
Once you have the object you can easily sort on the date object.
Using dayjs:
const dayjs = require('dayjs')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
const toTimestamp = (strDate) => {
return dayjs(strDate, 'DD.MM.YY HH:mm').unix()
}
I'm not sure why you are doing all the parsing and re-assembling into an ISO format manually? Without pulling in any libraries like suggested by #Manish Rawat you could do the parsing with a regex, might make it a bit more readable:
// as pointed out in the comments, this doesn't work as expected
// it will interpret the '4' as the month...
//console.log((new Date('4.12.22 15:17')).toISOString())
const toDate = function(str) {
const rex = /(?<day>\d+).(?<month>\d+).(?<year>\d+)\s+(?<hours>\d+):(?<minutes>\d+):?(?<seconds>\d+)?/;
const { day, month, year, hours, minutes, seconds } = (str.match(rex))?.groups || {
day: 0,
month: 0,
year: 0,
hours: 0,
minutes: 0,
seconds: 0
};
// console.log(str.match(rex)?.groups, year, month, day, hours, minutes, seconds);
return new Date(`20${year}-${month}-${day} ${hours}:${minutes}${seconds ? ':' + seconds : ''}`);
};
console.log(toDate('4.12.22 15:17'), toDate('4.12.22 15:17').getTime());
also, from there, what kind of sort are you planning to do? string based i assume? why not convert those dates to actual unix timestamps, e.g. number of seconds and compare those, so you won't have to deal with "weird" javascript string sorting things that might not yield the sort you are expecting?

How to Filter Data Array by Week Filter()

Currently trying to filter my data array by week, I have been able to filter by day quite easily however am struggling with dates between x and y (eg by week).
I have tried setting a start date and end date (today) and then trying to return the dates less than or equal to the start and end dates but am failing.
Data array date format: dd/mm/yyyy (01/01/2000)
The user will select which filter to use (hence switch() ) case 7 being filter by 7 days.
computed: {
appointments: function () {
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();
var data = this.$store.state.appointments;
this.filter1_color = "grey";
this.filter2_color = "grey";
switch (this.dateFilter) {
case 0:
break;
case 1:
console.log("case1: " + today)
return data.filter(word => word.date == today);
case 7:
/// WORKING /// (ex. edit)
var week = [];
var today = moment();
var sevenDaysBefore = today.subtract(7, 'days');
for (var i = 0; i < data.length; i++) {
let momentDate = moment(data[i].date, 'DD/MM/YYYY')
let newDate = momentDate.format("DD/MM/YYYY")
if (momentDate.isBetween(sevenDaysBefore, moment(), null, '[]')) week.push(data[i]);
}
return week
///
}
return data;
},
I need to filter the data to only show items in the array with dates equal to the dates in the last 7 days.
You can use method isBetween of moment js library with current date. You can subtract 7 days to current date with subtract(7, 'days').
You can check more about isBetween method in moment js library documentation. The third parameter of the method is the granularity, and it seems that in your case it should 'days'
const today = moment();
const sevenDaysBefore = moment().subtract(7, 'days');
console.log('Today is ' + today.format('MMM Do YYYY'));
console.log('Is ' + today.format('MMM Do YYYY') + ' included in the last seven days?');
console.log(today.isBetween(sevenDaysBefore, today, 'day', '[]'));
console.log('Is ' + sevenDaysBefore.format('MMM Do YYYY') + ' included in the last seven days?');
console.log(sevenDaysBefore.isBetween(sevenDaysBefore, today, 'day', '[]'));
const eightDaysBefore = moment().subtract(8, 'days');
console.log('Is ' + eightDaysBefore.format('MMM Do YYYY') + ' included in the last seven days?');
console.log(eightDaysBefore.isBetween(sevenDaysBefore, today, 'day', '[]'));
const oneDayAfter = moment().add(1, 'days');
console.log('Is ' + oneDayAfter.format('MMM Do YYYY') + ' included in the last seven days?');
console.log(oneDayAfter.isBetween(sevenDaysBefore, today, 'day', '[]'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js"></script>
If you don't want to or cannot use a library like moment.js, and also don't mind an ad-hoc implementation with certain restrictions:
Note
I recommend to use a library for working with Date objects, especially when it comes to parsing a string to a date. Too many things can go wrong when doing it by hand. If possible, use the answer of #f-CJ
These parts allow you to create a Date object from a string. However, the resulting Date is always converted to local time and the string needs to have a certain formatting (the one you showed in your question). If you need support for UTC, this won't work. Also, it cannot be used to parse a date string with ISO formatting.
const OFFSET_TO_UTC = new Date().getTimezoneOffset();
function parseDateString (dateString, sep) {
var parts = dateString.split(sep);
return parts.map(n => Number(n));
}
function localizeDate (pattern, parts) {
return pattern.reduce((acc, pat, i) => {
switch (pat) {
case 'd':
return Object.assign(acc, { day: parts[i] });
case 'm':
return Object.assign(acc, { month: parts[i] });
case 'y':
return Object.assign(acc, { year: parts[i] });
default:
return acc;
}
}, {});
}
function toDate (localized) {
return new Date(
localized.year,
localized.month - 1,
localized.day,
0, 0 - OFFSET_TO_UTC, 0);
}
function parseDate (pattern, sep, dateString) {
return toDate(localizeDate(pattern, parseDateString(dateString, sep)));
}
// try it:
const dStringUS = '04/04/2019'; // mm/dd/yyyy
const dStringDE = '04.04.2019'; // dd/mm/yyyy
const dateUS = parseDate(['m', 'd', 'y'], '/', dStringUS);
const dateDE = parseDate(['d', 'm', 'y'], '.', dStringDE);
console.log(dateUS);
console.log(dateDE);
Based on it, you can write yourself a generic filtering function:
const OFFSET_TO_UTC = new Date().getTimezoneOffset();
function parseDateString (dateString, sep) {
var parts = dateString.split(sep);
return parts.map(n => Number(n));
}
function localizeDate (pattern, parts) {
return pattern.reduce((acc, pat, i) => {
switch (pat) {
case 'd':
return Object.assign(acc, { day: parts[i] });
case 'm':
return Object.assign(acc, { month: parts[i] });
case 'y':
return Object.assign(acc, { year: parts[i] });
default:
return acc;
}
}, {});
}
function toDate (localized) {
return new Date(
localized.year,
localized.month - 1,
localized.day,
0, 0 - OFFSET_TO_UTC, 0);
}
function parseDate (pattern, sep, dateString) {
return toDate(localizeDate(pattern, parseDateString(dateString, sep)));
}
const data = [{
value: 0,
date: '04/05/2019'
}, {
value: 1,
date: '04/07/2019'
}, {
value: 2,
date: '03/07/2019'
}];
function filterByDatePattern (pattern, sep) {
return function (date, list) {
return list.filter(item => {
var itemDate = parseDate(pattern, sep, item.date);
return itemDate >= date;
});
}
}
const onlyUSUntil = filterByDatePattern(['m', 'd', 'y'], '/');
console.log(onlyUSUntil(new Date(2019, 3, 1), data));

What's the equivalent of a spread operator (...) for objects properties?

I am building a note taking app and require a way to pass the time the user takes to a constructor function that stores it. Here is the destination:
var NoteTime = function(minute, hour, day, month, year) {
var d = new Date();
this.millisec = d.getMilliseconds();
this.minute = minute || d.getMinutes();
this.hour = hour || d.getHours();
this.day = day || d.getDay();
this.month = month || d.getMonth();
this.year = year || d.getUTCFullYear();
}
var gatheredTime = {
minute: null,
hour: null,
day: null,
month: null,
year: null
}
I know I can passgatheredTime like this
var storeResult = new NoteTime(gatheredTime[prop1], gatheredTime[prop2]....etc)
But I would like to use less code and pass the value like I would were it an array:
var storeResult = new NoteTime(...gatheredTime)
Yes I can convert it to an array, but I would like to know if there is a better way.
Use Destructuring assignment
var NoteTime = function (gatheredTime) {
let {minute, hour, day, month, year} = gatheredTime;
var NoteTime = function(gatheredTime) {
let {
minute, hour, day, month, year
} = gatheredTime;
console.log(minute, hour, day, month, year);
// code here
};
var gatheredTime = {
minute: 10,
hour: 5,
day: 9,
month: 8,
year: 2016
};
NoteTime(gatheredTime);
Alternatively, the parameters can be directly destructed in arguments.
var NoteTime = function ({minute, hour, day, month, year}) {
You might need to turn your object into iterable by adding a [Symbol.iterator] method and then you can use for of loop or spread operator over a standard JS object.. Such as;
var o = {a:1,b:2,c:3},
a = [];
o[Symbol.iterator] = function*(){
var ok = Object.keys(this),
i = 0;
while (i < ok.length) yield this[ok[i++]];
};
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);
You can add the symbol iterators at the constructor so all of your instantiated objects will be iterable.

JavaScript: Fast parsing of yyyy-mm-dd into year, month, and day numbers

How can I parse fast a yyyy-mm-dd string (ie. "2010-10-14") into its year, month, and day numbers?
A function of the following form:
function parseDate(str) {
var y, m, d;
...
return {
year: y,
month: m,
day: d
}
}
You can split it:
var split = str.split('-');
return {
year: +split[0],
month: +split[1],
day: +split[2]
};
The + operator forces it to be converted to an integer, and is immune to the infamous octal issue.
Alternatively, you can use fixed portions of the strings:
return {
year: +str.substr(0, 4),
month: +str.substr(5, 2),
day: +str.substr(8, 2)
};
You could take a look at the JavaScript split() method - lets you're split the string by the - character into an array. You could then easily take those values and turn it into an associative array..
return {
year: result[0],
month: result[1],
day: result[2]
}
10 years later 😅,
If you want to extract Years from an array, this will help you:
jQuery:
function splitDate(date) {
newDate = [];
$.map(date, function (item) {
arr = item.split("-");
newDate.push(arr[0]);
});
return newDate;
}
Traditional way 😀 :
const splitDate = (date) => {
const newDate = [];
date.map(item => {
let arr = item.split("-");
newDate.push(arr[0]);
});
return newDate;
}
const dateArr = ['2013-22-22', '2016-22-22', '2015-22-22', '2014-22-22'];
const year = splitDate(dateArr);
console.log(year)

Categories