Moment.Js calculate difference datetime and show result - javascript

Library moments.js included.
I have a variable "lastMessage.created_at"
If it today's date to display then time in the format "h:mm a" if it was yesterday, display "Yesterday" or before that "D.M.Y", how do I do this ?

You could create a function to format input dates, these can be strings (in supported formats), Dates or moment objects.
We'll then output a different format based on whether the date is the same or after the start of today, the start of yesterday, or before that.
function formatDisplayDate(input) {
const dt = moment(input);
const startOfToday = moment().startOf('day');
const startOfYesterday = moment().startOf('day').subtract(1, 'day');
if (dt.isSameOrAfter(startOfToday)) {
return dt.format('h:mm a');
} else if (dt.isSameOrAfter(startOfYesterday)) {
return 'Yesterday';
} else {
// Before yesterday
return dt.format('D.M.Y');
}
}
const inputs = [ new Date().toLocaleString('sv'), new Date(Date.now() - 86400000).toLocaleString('sv'), new Date(Date.now() - 4*86400000).toLocaleString('sv') ];
for (let input of inputs) {
console.log(`Input: ${input}, output: ${formatDisplayDate(input)}`);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" referrerpolicy="no-referrer"></script>

Related

Check if given date is in last 3 weeks

I have a sample date:
const date = '10-03-2022';
I need to check if this date is longer than 3 weeks or not. Or speaking differently - I need to check if this date is in the last 3 weeks or older.
I was trying with date-fns but its not the result I expect.
import { formatDistance, subWeeks } from 'date-fns'
formatDistance(subWeeks(new Date(), 3), date)
I dont have to be honest any idea how to deal with such problem. Thats why I wanted to ask you here for help. Thanks!
You can use isAfter to compare against subWeeks. This will return true even if the date is in the future from now.
Alternatively you can use isWithinInterval to test if the date is within the period between now and three weeks before now. (not included in the cdn version available).
const dateIsWithinInterval = isWithinInterval(testDate,
{ start: subWeeks(new Date(), 3), end: new Date() })
You'll still need to parse your string into a valid Date object.
//import { isAfter, subWeeks } from 'date-fns';
const { isAfter, subWeeks } = dateFns; // cdn assignment
const dateString = '10-06-2022';
const [d, m, y] = dateString.split('-').map(n => parseInt(n, 10));
// months are 0 indexed so you need to subrtract 1.
const testDate = new Date(y, m - 1, d);
const dateIsAfter = isAfter(testDate, subWeeks(new Date(), 3));
console.log('isAfter:', dateIsAfter);
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/2.0.0-alpha0/date_fns.min.js" integrity="sha512-0kon+2zxkK5yhflwFqaTaIhLVDKGVH0YH/jm8P8Bab/4EOgC/n7gWyy7WE4EXrfPOVDeNdaebiAng0nsfeFd9A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Compare yyyy-mm-dd formatted date strings without the Date object possible?

If I define a date range using purely date strings in yyyy-mm-dd format, it appears comparison will work just fine without using the Date object:
const dateParts = '2021-12-15--2022-01-15'.split('--') // My date range
const startDate = dateParts.slice(0, 1) // '2021-12-15'
const endDate = dateParts.slice(1) // '2022-01-15'
const date = '2021-12-14'
// Test if date is within the range
console.log(date >= startDate && date <= endDate) // false
Using any date in the above example will test successfully if what I want is ensure that the date I'm looking for is within the range.
Why is this working? If javascript was, under the hood, evaluating the date strings as numbers, this should not be working. Is it maybe just implicitly assuming it's a date without me having to parse them using new Date(date)...?
Update: I'm not looking for solutions on how to do this using the Date object, I'd be more interested in examples where comparing dates this way would NOT work.
Your code works (Or if it looks like its working) because its just a basic string comparison and not the date comparison. To do a proper date comparison, you need to do the proper string to date conversion, and then compare them.
const dateParts = '2021-12-15--2022-01-15'.split('--') // My date range
const startDate = dateParts[0] // '2021-12-15'
const endDate = dateParts[1] // '2022-01-15'
const startDateArray = startDate.split("-").map(element => parseInt(element));
const endDateArray = endDate.split("-").map(element => parseInt(element));
const date = '2022-01-15'
const dateArray = date.split("-").map(element => parseInt(element));
// Test if date is within the range
console.log(new Date(dateArray[0], dateArray[1] - 1, dateArray[2]) >= new Date(startDateArray[0], startDateArray[1] - 1, startDateArray[2]) && new Date(dateArray[0], dateArray[1] - 1, dateArray[2]) <= new Date(endDateArray[0], endDateArray[1] - 1, endDateArray[2])) // false
This should solve your problem
const dateParts = '2021-12-15--2022-01-15'.split('--'); // My date range
const startDate = dateParts[1]; // '2021-12-15'
const endDate = dateParts[0]; // '2022-01-15'
const date = '2021-12-10'
// Test if date is within the range
alert(date < startDate && date < endDate)

Date conversion resulting into time zone issue

I am trying to get functionality - if the user entered date is less than the current date I need to show an error message on the screen, I implemented the following code which is working fine in my local system date but not working in other time zones. Can anyone please help in getting this.
I need to use only javascript or jquery. I was not supposed to use other libraries.
dateFormat = function(value, event) {
let newValue = value.replace(/[^0-9]/g, '').replace(/(\..*)\./g, '$1');
const dayOrMonth = (index) => index % 2 === 1 && index < 4;
// on delete key.
if (!event.data) {
return value;
}
return newValue.split('').map((v, i) => dayOrMonth(i) ? v + '/' : v).join('');
}
checkStart = function(value) {
var newDate = new Date().toISOString();
var inputDate = new Date(value).toISOString();
var today = new Date(newDate).setHours(0,0,0,0);
var userDate = new Date(inputDate).setHours(0,0,0,0);
if(userDate < today) {
$('#error-msg3').show();
$('#startDate').val('');
} else {
$('#error-msg3').hide();
}
}
<input type="tel" maxlength="10" id="startDate" name="startDate" placeholder="mm/dd/yyyy"
oninput="this.value = dateFormat(this.value, event)" onblur="checkStart(this.value)" required/>
<span id="error">Start date should not be lesser than the current date.</span>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
Server and Db May run on a different timezone, (UTC preferred ) and when you sen date as a string it doesn't have any timezone there instead it is just a string.
Try sending it as a timestamp or UTC date string
So that server and db will automatically convert it to their timzone and store it. and when any user fetch it from other time zone it will automatically converts to their timezone (but you store string it will just be treated as a string everywhere)
let d = new Date()
console.log(d.getTime())
//or get utc string
console.log(d.toUTCString())
Send this value to your server (API)
Your code runs entirely on the client so timezone is irrelevant.
In the OP there is:
var newDate = new Date().toISOString();
...
var today = new Date(newDate).setHours(0,0,0,0);
The conversion of Date to string to Date to number is inefficient and unnecessary. The following is equivalent:
let today = new Date().setHours(0,0,0,0);
Similarly for inputDate:
var inputDate = new Date(value).toISOString();
...
var userDate = new Date(inputDate).setHours(0,0,0,0);
is equivalent to:
let userDate = new Date(value).setHours(0,0,0,0);
All calculations are local so timezone is irrelevant. Also see Why does Date.parse give incorrect results?
Attempting to control user input using script is always fraught as there are many cases that are either impossible or impractical to code around. The use of a tel input for Dates is an example. The whole issue can be avoided by using a date input and setting a min value to today. Then users can't select a date before today and your issue is solved, e.g.
window.onload = function() {
let dateEl = document.getElementById('dateInput');
dateEl.min = new Date().toLocaleString('en-CA', {year:'numeric', month:'2-digit', day:'2-digit'});
}
<input id="dateInput" type="date">
If you are comparing the date sent by the user to a date on the server, then user system clock accuracy and timezone may be an issue, but that isn't explained in the OP.
If that is an issue, then you need to ask another question on that specific topic.
If you really want to manually control the input date and show an error message when invalid dates are selected, then parse the value from the date input and compare it to the start of today and go from there:
// Parse YYYY-MM-DD as local
function parseYMDLocal(s) {
let [Y, M, D] = s.split(/\D/);
return new Date(Y, M-1, D);
}
// Check if date in YYYY-MM-DD format is before today
function isBeforeToday(d) {
return parseYMDLocal(d) < new Date().setHours(0,0,0,0);
}
function checkValue() {
let errEl = document.getElementById('errEl');
errEl.textContent = '';
console.log(typeof this.value);
if (isBeforeToday(this.value)) {
errEl.textContent = 'Date must be today or later';
} else {
// do something else
}
}
window.onload = function() {
document.getElementById('dateInp').addEventListener('blur', checkValue, false);
}
#errEl {color: red}
<input id="dateInp" type="date"><span id="errEl"></span>

Convert moment.js to date-fns

I need to convert this from moment.js moment(date, 'DD MM YYYY').isBefore(moment()) to date-fns.
I tried isBefore(format(value, 'dd-MM-yyyy'), sub(new Date(), { days: 1 })). I mention that now I have to substract 1 day.
So the functionality will be to compare value which is the date given with currentDate - 1 day.
Essentially, check if future date is given, (future date includes current day).
Hope this is clear enough. My example doesn't work and I don't understand why.
Looks like you're using format instead of parse. isBefore accepts a number or Date not a string as its first argument.
See example:
function compareDate(value: string) {
return isBefore(
parse(value, 'dd-MM-yyyy', new Date()),
sub(new Date(), { days: 1 })
);
}
const test = compareDate('31-12-2020');
console.log(test);
As requested in comments
We can run the value against a function that replaces all / and \s to -.
function unifyDateString(value: string) {
try {
return value.split("/").join("-").split(" ").join("-");
} catch {
return value;
}
}
function compareDate(value: string) {
return isBefore(
parse(unifyDateString(value), "dd-MM-yyyy", new Date()),
sub(new Date(), { days: 1 })
);
}
const one = compareDate("31-12-2020");
const two = compareDate("31/12/2020");
const three = compareDate("31 12 2020");
console.log(one);
console.log(two);
console.log(three);

Date formatting and comparing dates

I want to check to see if a date is before today. If it is then I want to display the date but not the time, if it is today then I want to display the time and not the date. The date I am checking is in the dd-mm-yyy hh:mm format and so they do not compare.
Please see what I have below so far:
var created = '25-05-2012 02:15';
var now = new Date();
if (created < now) {
created_format = [ format the date to be 25-05-2012 ]
} else {
created_format = [ format the date to be 02:15 ]
}
I have tried using now.dateFormat() and now.format() after seeing these in other examples but I get "is not a function" error messages.
Start by getting the parts of your date string:
var created = '25-05-2012 02:15';
var bits = created.split(/[-\s:]/);
var now = new Date();
// Test if it's today
if (bits[0] == now.getDate() &&
bits[1] == (now.getMonth() + 1) &&
bits[2] == now.getFullYear() ) {
// date is today, show time
} else {
// date isn't today, show date
}
Of course there are other ways, but I think the above is the easiest. e.g.
var otherDate = new Date(bits[2], bits[1] - 1, bits[0]);
now.setHours(0,0,0,0);
if (otherDate < now) {
// otherDate is before today
} else {
// otherDate is not before today
}
Similarly, once you've converted the string to a date you can use getFullYear, getMonth, getDate to compare with each other, but that's essentially the same as the first approach.
You can use getTime method and get timestamp. Then you can compare it with current date timestamp.

Categories

Resources