MomentJs invalid date from datepicker - reactjs

I Am trying to format a date from react datepicker, the value going in is 1441062000000
onChangeStartDate: function(value) {
this.setState({
startDate: moment(value)
})
},
When I check the date in dev tools I get a moment invalid date, can anyone tell me how I can create a date from the value?
I'm using the value 1443135600000 with format, but still getting invalid date:
onChangeEndDate: function onChangeEndDate(value) {
console.log(moment(value, ConfigProvider.getKey('dateFormat')));

You might need to pass the format as a second argument to moment - in case of react date picker, it defaults to 'x', e.g. unix timestamp:
this.setState({
startDate: moment(value, 'x')
})
If you omit the second argument, moment tries to parse the input by looking for ISO 8601 formats, but a unix timestamp will cause this algorithm to fail. That's why you need to specify the format explicitly.
The other way would be to configure your date picker to emit changes in an IS 8601 compliant format, for example format='YYYY-MM-DD'.

Related

react-intl FormattedDate component giving Invalid Date changed to en-GB locale

I have my date formatted like this
let formattedDate = new Date(updated_at).toLocaleDateString('en-US', { timeZone: 'UTC' })
Then I have the FormattedDate component from 'react-intl' package used like this
<FormattedDate value={formattedDate} />
Then It renders the formattedDate value like this on the browser(MM/DD/YYY)
Now I'd like to change it to en-GB date format(DD/MM/YYYY) so I did this,
let formattedDate = new Date(updated_at).toLocaleDateString('en-GB', { timeZone: 'UTC' })
But then I get invalid date on my table after that, but some of the rows render with date with now the correct format I wanted.
Here are the errors by the way in the browser console.
Error: [#formatjs/intl Error FORMAT_ERROR] Error formatting date.
Invalid time value
RangeError: Invalid time value
at formatDate (dateTime.js:50:1)
And If I console.log those problem dates before being formatted, just in their raw form here they are:
2022-09-22T06:52:32.870184Z
2022-09-22T03:04:54.983147Z
2022-09-20T08:09:22.845208Z
Weird though, if I console.log those three using this my line of code
let formattedDate = new Date(updated_at).toLocaleDateString('en-GB', { timeZone: 'UTC' })
Then I'll get a proper value
22/09/2022
So, I'm really stuck how to fix this, as the other dates can be formatted correctly with my approach, but the first three dates on my table won't. Though they are the same in format as I can tell. Thanks in advance for any help.

react-day-picker changing default date format prevents entering date

I have just started using the react-day-picker library. I have the following code sandBox which is a fork of the range with 2 inputs example,
https://codesandbox.io/s/w6vnlox29l
I have it working the way I want but I want to input the dates as MM/DD/YYYY instead of the default format, YYYY-MM-DD. When I add the following attributes
<DayPickerInput
value={from}
format="M/D/YYYY"
formatDate={formatDate}
parseDate={parseDate}
placeholder="MM/DD/YYYY"
onDayChange={this.handleFromChange}
dayPickerProps={{
selectedDays: [from, { from, to }],
modifiers,
disabledDays: {
after: new Date(),
},
numberOfMonths: 2,
toMonth: new Date(),
}}
/>
I can no longer correctly enter the date in the input field the date. When I remove the format, formatDate and parseDate attributes the date picker input functions the way I expected. I have read the documentation but think I may be missing something simple. How can I use the input text box and date picker with dates formatted as MM/DD/YYYY?

React-datepicker changes date but not time

I'm using Moment.js with react-datepicker. It works as intended in terms of the date transformation to ISO-8601, but I can't get it compliant with the time.
Here's my component:
Stated initially:
this.state = {
from: moment().subtract(7, "days"), // Default 1 week back
to: moment(), // Current date
};
The component itself:
<DatePicker
dateFormat="DD-MMM HH:mm"
dropdownMode="select"
selected={this.state.from}
onChange={this.handleFromChange}
/>
And the onchange trigger:
handleFromChange(date) {
this.setState({
from : date
});
}
I think my issue is the dateFormat; The DD-MMM are easily transformed to ISO-8601 by calling using the ECMAScript function toISOString() before posting it to some backend services. But how do I get the time to go with it?
The user(myself, testing) can chance the time on the datepicker itself, but it won't register in the state. Simply it will just pick the current time, or current time 1 week ago(as per the moment from/to initial states). The date, i can change also, but the time remains the same(current time).
How do I change the dateFormat so it takes the time input from the user? How do I make it ISO 8601 compliant per default in the dateFormat attribute?
Edit: I just tested with setting "from" to subtract 5 minutes at such:
this.state = {
from: moment().subtract(5, "minutes"),
to: moment(), // Current date
};
And it formats it correctly when I post it. Seems strange. It must be related to the onChange function then?
Try using dateFormat="dd-MMM hh:mm" and change onChange function to this to avoid error.
handleFromChange(date) {
this.setState({
from : date || ""
});
}

Datatables/MomentJS - Change date format when locale changes

I'm trying to display a properly formatted date in a Datatable column. I'm using MomentJS to detect and format the cell properly, as it comes as a yyyyMMdd (i.e. 20051201) string from the database:
columns: [
{
data: "fechaPago",
"render": function(data){
return (moment(data).isValid()) ? moment(data).format("DD/MM/YYYY") : "-";
}
},
]
Which works exactly as expected:
Now, I'm struggling to implement a more flexible approach, and let the current locale determine the format. We have 3 available languages in our webapp, and I want the Datatable to detect the current language and change the format (from dd/MM/yyyy to MM/dd/yyyy, if it's in English).
I have tried to use 'LLLL' as the format, but it returns the whole date with letters, and I can't figure out how to modify it.
You can use moment locale(String) function to set locale for a moment oblect or moment.locale(String) to set moment locale globally.
To get localized day, month and year use L token in the format().
Your code will be like the following:
columns: [
{
data: "fechaPago",
"render": function(data){
var locale = // get current locale code
return (moment(data).isValid()) ? moment(data).locale(locale).format("L") : "-";
}
},
]
Remember to use moment-with-locales.js (or import required locales).

How do I convert dates returned from webapi in string format to javascript date format for AngularJs

I have a number of .net webApi actions returning dates that are deserialised into JSON. My angular application then consumes these date strings for display\edit or as the ngModel in a variety of date directives. Many of these directives require a javascript date object and not a string representation of a date. How do serialise the date string back to javascript date for all returned webapi data?
N.B. I have tried a variety of regExs that proport to be ISO 8601 compliant, but for every one I use there are a bunch of use cases that fail. The cases I require are as follows:
should not convert non dates (string) e.g. 'http://blah/'
should not convert non dates (integer) e.g. 2015
should not convert bad dates e.g. '2009-05-19T14a39r'
should not convert partial bad date from string to date e.g. '1'
should not convert a string that looks like a year e.g. '2015'
should convert date from string to date e.g. '2015-09-09'
should convert date with time from string to date with time e.g. '2009-05-19T14:39'
should convert date with time from string to date with time including seconds e.g. '2009-05-19T14:39:23'
should convert date with time to the millisecond from string to date with time with milliseconds e.g. '2016-06-09T13:02:39.957'
should convert date with time from string to date with time in UTC e.g. '2009-05-19T14:39Z'
should not convert a date which is part of a longer string e.g. 'Should not convert 2015-12-12T00:00:00Z as this is part of a longer string'
So, firstly in order to intercept and convert all string dates to javascript dates we need angular to do the interception and replacing. For this we can use an interceptor on the httpProvider to ensure our code runs on all returned http responses before any other code is executed.
var app = angular.module('app');
app.config(configureProviders);
configureProviders.$inject = ['$httpProvider'];
function configureProviders($httpProvider) {
configureHttp($httpProvider);
}
function configureHttp(httpProvider) {
// add all http interceptors
httpProvider.interceptors.push('dateDeserialiserInterceptor');
}
ok so now we have our interceptor registered, but we need some code to make it work:
(function () {
var module = angular.module('myApp.interceptors');
module.factory('dateDeserialiserInterceptor', function () {
function convertDateStringsToDates(input) {
// Ignore things that aren't objects.
if (typeof input !== "object") return input;
for (var key in input) {
if (!input.hasOwnProperty(key)) continue;
var value = input[key];
// Check for string properties which look like dates.
if (typeof value === "string" && (moment(value, moment.ISO_8601).isValid())) {
input[key] = moment(value, moment.ISO_8601).toDate();
} else if (typeof value === "object") {
// Recurse into object
convertDateStringsToDates(value);
}
}
};
return {
response: function (response) {
convertDateStringsToDates(response);
return response;
}
};
});
})();
So the above code was originally taken off the internet somewhere and had a manual regEx comparison. The regEx was described as ISO 8601 compliant, but I found a multitude of examples where it wasn't. This now relies on an Open Source library momentJs to determine if the date is ISO 8601 compliant and to do the conversion. If the date isn't compliant the string value is simply returned. ISO 8601 is a great standard to use (as it covers a multitude of cases) and is much better than hard coding any expected particular format which may lead you down a path of 'oh...it's missed one'.
At the moment this is parsing all returned response object values for potential dates. I thought about improving this by explicitly marking the request with the response properties that we expect to be dates. That way we wouldn't have to try\parse everything (which is slow) and also run the risk that something we don't want to convert gets converted. However that approach is a little messy and would litter many requests. I like this approach for now and it seems to work. Happy for it to be improved!
Here is an Angular 2+ solution. This assumes the date from the API is in ISO format:
In your Component:
// call to your data service
this.dataService.getSomeData().map(records => {
records.map(record => {
//call to shared service date conversion function
this.dataService.covertISOFieldstoDateObjects(record);
});
return records;
}).subscribe(x => {
// processed records will now have date objects for any date properties
this.records = x;
}, error => {
...
});
In your Service:
covertISOFieldstoDateObjects(currentObj) {
const entries = Object.entries(currentObj);
for (const [key, value] of entries) {
const isDate = moment(value, moment.ISO_8601).isValid();
if (isDate) {
currentObj[key] = moment(value as string, 'YYYY-MM-DD HH:mm'); // Use this to get UTC and ignore timezone (good when you need just the date)
currentObj[key] = moment(value as string, 'YYYY-MM-DD HH:mmZ'); // Use this to include timezone adjustment
}
}
return currentObj;
}

Resources