I have 2016-10-21T13:47:02.922452 as ISO string from backend server.
My timezone is +0530 GMT i.e Offset is +530 (ahead of GMT).
When i use angular date expression like this
{{'2016-10-21T13:47:02.922452'| date:'medium':'+530'}}
I expected output to be = Oct 21, 2016 7:17:02 PM
but it prints
Oct 21, 2016 1:47:02 PM instead.
I am confused for what am i doing wrong here.
Do something like this
var d = new Date('2016-10-21T13:47:02.922452');
console.log(d)
Answering myself !
The easiest way that i figured out ! Make a custom filter
app.filter('IST', function($filter){
return function(val){
var date = new Date(val);
return $filter(date, 'medium');
}
})
Then use filter in expression like this -
{{'2016-10-21T13:47:02.922452'| IST}}
Custom filter will automatically convert ISO format string to Date object (browser timezone will automatically take care of timezone conversion.)
Date pipe transforms the date string you are passing ('2016-10-21T13:47:02.922452') to a Date object and then applies the time zone offset.
¿Whats the problem? When transforming '2016-10-21T13:47:02.922452' to a Date, it supposes that the date is in your local time, so the final calculation is wrong. For example, I am in +0200 so the transformation will be:
2016-10-21T13:47:02.922452 -> 2016-10-21T13:47:02.922452+0200 (Date object)
2016-10-21T13:47:02.922452+0200 -> 2016-10-21T18:17:02.922452+0530 (date changes with offset difference 0530-0200)
If your backend date is always in GMT timezone, just add Z to your date string: 2016-10-21T13:47:02.922452Z. This way, when creating the Date it will understand that the initial timezone is +0000
Solution:
{{'2016-10-21T13:47:02.922452Z' | date:'medium':'+0530'}}
Related
I have this angularJS view that I want to render a date with this format: MMM YYYY
My data is giving me the modified date as a string like "20210410072612"
I have:
{{item.default['Date modified'].substr(4,2) | date:'MMM'}} {{item.default['Date modified'].substr(0,4)}}
The results from this are: Jan 2021
The correct result should be Apr 2021 since when I remove the date:'MMM' filter I got 04 2021 Any idea what I'm doing wrong?
I manage to accomplish the desired results creating my own filter as a function and call it like this.
{{ getMonthName( item.default['Date modified'].substr(4,2) ) }} {{item.default['Date modified'].substr(0,4)}}
The issue was that I was passing a string with the zero for the month number and the result would always be Jan
For example, using a date and time control, the user selects a date and time, such that the string representation is the following:
"6-25-2012 12:00:00 PM"
It so happens that this user is in the EST time zone. The string is passed to the server, which translates it into a .NET DateTime object, and then stores it in SQL Server in a datetime column.
When the date is returned later to the browser, it needs to be converted back into a date, however when the above string is fed into a date it is losing 4 hours of time. I believe this is because when not specifying a timezone while creating a JavaScript date, it defaults to local time, and since EST is -400 from GMT, it subtracts 4 hours from 12pm, even though that 12pm was meant to be specified as EST when the user selected it on a machine in the EST time zone.
Clearly something needs to be added to the original datetime string before its passed to the server to be persisted. What is the recommended way of doing this?
Don't rely on JavaScript's Date constructor to parse a string. The behavior and supported formats vary wildly per browser and locale. Here are just some of the default behaviors if you use the Date object directly.
If you must come from a string, try using a standardized format such as ISO8601. The date you gave in that format would be "2012-06-25T12:00:00". The easiest way to work with these in JavaScript is with moment.js.
Also, be careful about what you are actually meaning to represent. Right now, you are passing a local date/time, saving a local/date/time, and returning a local date/time. Along the way, the idea of what is "local" could change.
In many cases, the date/time is intended to represent an exact moment in time. To make that work, you need to convert from the local time entered to UTC on the client. Send UTC to your server, and store it. Later, retrieve UTC and send it back to your client, process it as UTC and convert back to local time. You can do all of this easily with moment.js:
// I'll assume these are the inputs you have. Adjust accordingly.
var dateString = "6-25-2012";
var timeString = "12:00:00 PM";
// Construct a moment in the default local time zone, using a specific format.
var m = moment(dateString + " " + timeString, "M-D-YYYY h:mm:ss A");
// Get the value in UTC as an ISO8601 formatted string
var utc = m.toISOString(); // output: "2012-06-25T19:00:00.000Z"
On the server in .Net:
var dt = DateTime.Parse("2012-06-25T19:00:00.000Z", // from the input variable
CultureInfo.InvariantCulture, // recommended for ISO
DateTimeStyles.RoundtripKind) // honor the Z for UTC kind
Store that in the database. Later retrieve it and send it back:
// when you pull it from your database, set it to UTC kind
var dt = DateTime.SpecifyKind((DateTime)reader["yourfield"], DateTimeKind.Utc);
// send it back in ISO format:
var s = dt.ToString("o"); // "o" is the ISO8601 "round-trip" pattern.
Pass it back to the javascript in moment.js:
// construct a moment:
var m = moment("2012-06-25T19:00:00.000Z"); // use the value from the server
// display it in this user's local time zone, in whatever format you want
var s = m.format("LLL"); // "June 25 2012 12:00 PM"
// or if you need a Date object
var dt = m.toDate();
See - that was easy, and you didn't need to get into anything fancy with time zones.
Here, I think this is what you are looking for:
How to ignore user's time zone and force Date() use specific time zone
It seems to me that you can do something like this:
var date = new Date("6-25-2012 12:00:00 PM");
var offset = date.getTimezoneOffset(); // returns offset from GMT in minutes
// to convert the minutes to milliseconds
offset *= 60000;
// the js primitive value is unix time in milliseconds so this retrieves the
// unix time in milliseconds and adds our offset.
// Now we can put this all back in a date object
date = new Date(date.valueOf() + offset);
// to get back your sting you can maybe now do something like this:
var dateString = date.toLocaleString().replace(/\//g,'-').replace(',','');
Blame the JSON.Stringfy()... and do:
x = (your_date);
x.setHours(x.getHours() - x.getTimezoneOffset() / 60);
I am using a filter before sending the date to the server:
vm.dateFormat = 'yyyy-MM-dd';
dateToSendToServer = $filter('date')(dateFromTheJavaScript, vm.dateFormat);
I have an object which I get from a server, and this object has a property: obj.year: "2017", for example. The property is a number.
I need to display only the last two digits of the year.
When I format it in the HTML like this:
{{obj.year | date : 'yy'}}
it shows :70. I tried with all kind of built Angular year filters and I tried it with a moment js formatting function:
function formatYear(year) {
return moment(year).format('YY');
}
But it still returns the year 1970.
I don't get why it returns this year, and this happens only when it's being formatted? If I don't apply any formatting on it, it returns the normal value of the object - 2017
The documentation for the date filter explains why this happens. It's expecting the value you supply to be a Date object, a date string, or a number in milliseconds.
Here is their description:
Date to format either as Date object, milliseconds (string or number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is specified in the string input, the time is considered to be in the local timezone.
The reason you are getting 1970 is b/c the date filter is taking your year, 2017, and interpreting it as the number of miliseconds since the epoch or unix time.
To make the date filter work, you can just convert your year value into a Date (or similar approach when using moment):
var date = new Date(obj.year, 0,1); // Jan 1
The reason why {{obj.year | date : 'yy'}} outputs 70 is because you are passing the number 2017 to angular's date filter and so doing the equivalent of new Date(2017) which returns a date and time that is 2017 milliseconds from 1970-01-01 00:00:00:000 or to be precise 1970-01-01 00:00:02:017. So when you run that through angular's date filter with the yy formatting string you get the last two digits of the year which is of course 70.
To offer an alternative solution, you could use angular's limiTo filter:
{{ obj.year | limitTo : 2 : 2 }}
As other answers stated you are getting 70 instead of 17 because angular date filter accepts:
Date object, milliseconds (string or number) or various ISO 8601 datetime string
So your input is interpreted as number of milliseconds since 1 January 1970 00:00:00, basically it is equivalent to:
console.log(new Date(2017)); // 1970-01-01T00:00:02.017Z
Your formatYear function using moment has the same logic, so it gaves the same wrong result. If you use moment parsing specifying format (moment(String, String); instead of moment(Number);), your input will be treated as string and you will have the right output:
function formatYearBad(year) {
// uses moment(Number)
return moment(year).format('YY');
}
function formatYearOk(year) {
// uses moment(String, String)
return moment(year, 'YYYY').format('YY');
}
console.log( formatYearBad(2017) ); // 70
console.log( formatYearOk(2017) ); // 17
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
To use the right moment logic inside you angularjs view, you have to use angular-moment library. You can use amParse to specify the format of your input string (four digit year in your case) and amDateFormat to specify output format (two digit year in your case). Here a working example:
angular.module('MyApp',['angularMoment'])
.controller('AppCtrl', function($scope) {
$scope.obj = {
year: "2017"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-moment/1.0.1/angular-moment.min.js"></script>
<div ng-app="MyApp" ng-controller="AppCtrl">
{{obj.year | amParse:'YYYY' | amDateFormat:'YY'}}
</div>
So this is how my code looks like
cropref.child(mycrop.name).push({
cropname:mycrop.name,
croplocation:mycrop.location,
cropplantdate:mycrop.plantdate.toString(),
cropharvestdate:mycrop.harvestdate.toString(),
})
mycrop.harvestdate and mycrop.plantdate are both date inputs from my html
<input type="date" ng-model='mycrop.harvestdate'>
<input type="date" ng-model='mycrop.harvestdate'>
to be able to put the data on my Firebase database , I need to convert it first into string
cropplantdate:mycrop.plantdate.toString(),
but the data on my Firebase database includes time and timezone
sample data
Sat Dec 12 2020 00:00:00 GMT+0800 (Malay Peninsula Standard Time)
so once I call the data from my database, I can't filter it since it's not a date anymore but a string.
How do I solve this problem so that I can filter date (which is converted to string) stored inside my database
Two options
1) Store the date in a more generic, but human readable format, so right now would be Sunday November 27 at 09:13:38
20161127091338
2) Store the date as a unix timestamp (in milliseconds) using
(new Date).getTime() / 1000
There are a lot of variants to #2 so do some research to see which is best for your use case.
You can save either answer as a string but #1 would be more easily searchable since queries wouldn't require any kind of conversions - to see todays events
queryStartingAt("20161127") and queryEndingAt("20161127")
You need to convert the date first in your Format. You can use SimpleDateFormatFormat for that.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Now you can easily format your date to this format
String mynewdate = sdf.format(mycrop.plantdate.getTime());
The Output for today would be:
2016-11-27
Of course you can reverse that back to a Calendar. I do it this way:
public static Calendar fromStringtoCalendar(String datestring){
int year = Integer.valueOf(datestring.substring(0, 4));
int month = Integer.valueOf(datestring.substring(5, 7)) -1;
int day = Integer.valueOf(datestring.substring(8, 10));
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
return calendar;
}
I have a moment.js object generated from fullcalendar in BST that looks like this:
console.log(momentSelected)
//Moment {_isAMomentObject: true, _isUTC: true, _offset: 0, _locale: f, _d: Tue May 03 2016 01:00:00 GMT+0100 (BST)…}
I don't want a BST time but a UTC time that looks like this:
console.log(momentSelected.format('YYYY-MM-DD HH:mm Z'));
//2016-05-03 00:00 +00:00
Now I need to convert it into a Date object:
$scope.date = new Date(momentSelected.format('YYYY-MM-DD HH:mm Z'));
console.log($scope.date);
//Wed May 04 2016 01:00:00 GMT+0100 (BST)
The last output is wrong... I want Wed May 04 2016 00:00:00+00:00 (UTC)
You can create a Date object using the toDate function on the moment object.
$scope.date = momentSelected.toDate();
However, you must recognize that the nature of the Date object is that it will always represent UTC internally, and its toString function will always reflect the local time zone where the code is running.
If your local time zone is UK (alternating between GMT and BST for daylight saving time), then it is impossible to get (UTC) time in the string produced by console.log($scope.date);, regardless of how you created that date.
This is why it is better to use moment's format function and display that string directly. A moment can reflect UTC, local time, and other time zones. A Date object cannot.
Also, you should pay no attention to the underscore-prefixed internal fields of a moment object. Use the public API instead. See the moment user guide.