Datatables/MomentJS - Change date format when locale changes - angularjs

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).

Related

RangeError: Invalid Time Value after incorporating local storage

I'm working on a forum and using a form that the user fills out I'm storing data as an object inside an array. The data I'm storing includes the title of a topic, the message, the author and the date. That data is stored inside a topic array which I'm mapping on screen so the user can see all current topics, who created them and the date in which they were created. I also started to use localStorage so I can save my data and test to make sure everything looks good after my page refreshes.
const [topic, setTopic] = useState(() => {
const topicJson = localStorage.getItem("topic");
return topicJson ? JSON.parse(topicJson) : [];
});
const updatedTopic = [
...topic,
{
title: title,
message,
author: "Dagger",
date: new Date(),
},
];
setTopic(updatedTopic);
};
That's the code that I'm using which works as intended however when I map through the array to post the data on screen, I'm having trouble with showing the date. I'm using date-fns because it displays the date exactly how I want it.
Example: 2/19 9:39PM. That's how I want the date to look on screen and using date-fns has been the only thing I've found that makes it look that way.
{topic
.sort((a, b) => b.date - a.date)
.map(({ date }, index) => (
<tr>
{<td>{format(date, "M/dd h:mma")}</td>}
</tr>
))}
That's the code I'm using to map through the array to show the date. Before adding localStorage it worked fine. When I remove the format and show the code as date it works but including format gives me this error:
throw new RangeError('Invalid time value');
// Convert the date in system timezone to the same date in UTC+00:00 timezone.
// This ensures that when UTC functions will be implemented, locales will be compatible with them.
I think your are using Date object to store date and JSON.stringify cant handle Date object. You should to use Date method.
Easy way just save not Date object but ISO string.
date.toISOString()
And in table:
{<td>{format(parseISO(date), "M/dd h:mma")}</td>}

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.

How to format the date string according to the country in angular?

I had the following code where i get the data from JSON response. I want to change the date string format w.r.t to country locale. I'm using angular-translate for translations and added all the strings in respective locale json file. For example i want to add the date format (dd/mm/year) for es_ES(spanish) locale and (mm/dd/year) for en_US. Can i add the date format by any chance in the Json file or how can i add a filter to format in markup itself? Is it possible at all?
//Sample Html markup
<tr ng-repeat="data in data.list">
<td>{{data.originalDate}}</td>
<td>{{data.expiryDate}}</td>
</tr>
//sampleJsonResponse
{
"data": [
"{originalDate:\"09/30/2017\",expiryDate:\"10/30/2018\"}"
]
}
Thanks
You can use just javascript to transform date to different locale:
first you will need to create date object with (new Date(yourdate)):
let date = new Date('10/30/2018');
then set date to specific locale use dash instead of underscore
date.toLocaleString('es-ES')
for your purposes you can just do:
new Date(data[0].originalDate).toLocaleString('es-ES')
new Date(data[0].expiryDate).toLocaleString('es-ES')
or do a map on entire data like this:
data.map(value => {
return {
originalDate: new Date(value.originalDate).toLocaleString('es-ES'),
expiryDate: new Date(value.expiryDate).toLocaleString('es-ES')
}
});
More info here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
For all other advanced date manipulation I would suggest momentJS: https://momentjs.com/
I'm using sugar.js javascript library for date formatting and also it has other general functions such as number and string formatting which serves well in my code base.

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;
}

MomentJs invalid date from datepicker

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'.

Resources