Angular2+ How to display milliseconds from date? - javascript

I was using a custom pipe for displaying time, and now I tried to change it so that I could also display milliseconds:
{{log.LogDate|jsonDate|date:'dd.MM.yyyy HH:mm:ss.sss'}}
The pipe itself:
if (typeof (value) === 'string') {
if (value.includes('/Date('))
return new Date(parseInt(value.substr(6)));
}
return value;
However, milliseconds have the value of seconds:
log.LogDate: 2017-05-08T15:45:38.2527293+
02:00
Output from pipe: 08.05.2017 15:45:38.38
Full jsonDate pipe(no format): 2017-05-08T15:45:38.2527293+02:00
I am new to Javascript, and I am not sure if this is an Javascript or an Angular issue, however, I would like it to work inside Angular.
Is it possible to do this using pipes, or is there another/better way to do this?

Since angular 5 you can use SSS to add milliseconds to your date.
See https://angular.io/api/common/DatePipe
So your example would look like
{{log.LogDate|jsonDate|date:'dd.MM.yyyy HH:mm:ss.SSS'}}
Changelog for angular 5:
- [...]
- fractional seconds are now supported with the format S to SSS.
- [...]

It's an Angular issue. AngularJS supports milliseconds, but Angular (2+) does not (GH issue).
You can very well drop the date pipe and use only your custom one for this task. Your example however doesn't seem to handle dates very well. Without going into details I suggest you use some external library to do the formatting
for you inside your pipe. Otherwise it would be a lot of effort for little reward. My personal weapon of choice is Moment.js
After importing it correctly you would simply use:
moment(value).format('DD.MM.YYYY HH:mm:ss.SSS');
If you want a dirty way out of this without importing external libraries, you could use Angular date pipe as it is (with seconds only) and then pipe it to add milliseconds on your own.

Another possibility is to stay with angulars pipe and extract the milliseconds via javascript-method:
{{ Datetime | date:'dd.MM.yyyy HH:mm:ss' }}.{{ getMillies(Datetime) }}
----
public getMillies(input: Date): number
{
return new Date(input).getMilliseconds();
}
With Angular 5, a new Date-Pipe is in progress, to support M

Related

moment.js mock local() so unit test runs consistently

I want to test the following piece of code. I am wondering if there is a way to mock moment.js or force it to think my current location is America/New_York so that my unit test doesn't fail in gitlab.ci runner which may be in various geographical locations?
const centralTimeStartOfDay = moment.tz('America/Chicago').startOf('day');
const startHour = centralTimeStartOfDay
.hour(7)
.local()
.hour();
Basically I want to hard code my timezone to be America/New_York and want this function to behave consistently.
Edit:
I tried:
Date.now = () => new Date("2020-06-21T12:21:27-04:00")
moment.tz.setDefault('America/New_York')
And still, I get the same result. I want to mock the current time so startHour returns a consistent value.
The problem
So there is no one line answer to this question. The problem is a fundamental one to javascript, where you can see dates in one of two ways:
UTC (getUTCHours(), getUTCMinutes() etc.)
local (i.e. system, getHours(), getMinutes() etc.)
And there is no specified way to set the effective system timezone, or even the UTC offset for that matter.
(Scan through the mdn Date reference or checkout the spec to get a feeling for just how unhelpful this all is.)
"But wait!" we cry, "isn't that why moment-timezone exists??"
Not exactly. moment and moment-timezone give much better / easier control over managing times in javascript, but even they have no way to know what the local timezone Date is using, and use other mechanisms to learn that. And this is a problem as follows.
Once you've got your head round the code you'll see that the moment .local() method (prototype declaration and implementation of setOffsetToLocal) of moment effectively does the following:
sets the UTC offset of the moment to 0
disables "UTC mode" by setting _isUTC to false.
The effect of disabling "UTC mode" is to mean that the majority of accessor methods are forwarded to the underlying Date object. E.g. .hours() eventually calls moment/get-set.js get() which looks like this:
export function get(mom, unit) {
return mom.isValid()
? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
: NaN;
}
_d is the Date object that the moment (mom) is wrapping. So effectively for a non-UTC mode moment, moment.hours() is a passthrough to Date.prototype.getHours(). It doesn't matter what you've set with moment.tz.setDefault(), or if you've overridden Date.now(). Neither of those things are used.
Another thing...
You said:
Basically I want to hard code my time to be America/New_York and want this function behaves consistently
But actually, that is not generally possible. You are using Chicago, which I imagine has offset shifts in sync with New York, but e.g. the UK shifts at a different time from the US, so there are going to be weeks in the year where your test would fail if you were converting from a US timezone to a UK timezone.
The solutions.
But this is still frustrating, because I don't want my devs in Poland and the west coast of America to have breaking local tests because my CI server is running in UTC. So what can we do about it?
The first solution is a not-a-solution: find a different way of doing the thing you're doing! Generally the use cases for using .local() are quite limited, and are to display to a user the time in their current offset. It's not even their timezone because the local Date methods will only look at the current offset. So most of the time you'd only want to use it for the current time, or if you don't mind if it's wrong for half of the Date objects you use it for (for timezones using daylight savings). It could well be better to learn the timezone the user wants through other means, and not use .local() at all.
The second solution is also a not-a-solution: don't worry about your tests so much! The main thing with displaying a local time is that it works, you don't really care what it is exactly. Verify manually that it's displaying the correct time, and in your tests just verify that it returns a reasonable looking thing, without checking the specific time.
If you still want to proceed, this last solution at least makes your case work and a few others, and it's obvious what you need to do if you find you need to extend it. However, it's a complicated area and I make no guarantees that this will not have some unintended side-effects!
In your test setup file:
[
'Date',
'Day',
'FullYear',
'Hours',
'Minutes',
'Month',
'Seconds',
].forEach(
(prop) => {
Date.prototype[`get${prop}`] = function () {
return new Date(
this.getTime()
+ moment(this.getTime()).utcOffset() * 60000
)[`getUTC${prop}`]();
};
}
);
You should now be able to use moment.tz.setDefault() and using .local() should allow you to access the properties of the datetime as though it thought the local timezone was as configured in moment-timezone.
I thought about trying to patch moment instead, but it is a much more complicated beast than Date, and patching Date should be robust since it is the primitive.
try
// package.json
{
"scripts": {
"test": "TZ=EST jest"
}
}
Brilliant daphtdazz - thank you! To clarify for those who follow, this is the full solution I used to control the current date, timezone, and with daphtdazz's help - the local() behavior in moment:
import MockDate from 'mockdate';
const date = new Date('2000-01-01T02:00:00.000+02:00');
MockDate.set(date);
[
'Date',
'Day',
'FullYear',
'Hours',
'Minutes',
'Month',
'Seconds',
].forEach(
(prop) => {
Date.prototype[`get${prop}`] = function () {
return new Date(
this.getTime()
+ moment(this.getTime()).utcOffset() * 60000
)[`getUTC${prop}`]();
};
}
);
const moment = require.requireActual('moment-timezone');
jest.doMock('moment', () => {
moment.tz.setDefault('Africa/Maputo');
return moment;
});

momentjs override the default global date for today

I'd like to set a default time for momentjs. For instance the default behavior is:
moment().format('YYYY-MM-DD') // returns current date
What I'd like to do is to override the current date to some other date, i.e. 2017-03-01, so whenever I do
moment().format('YYYY-MM-DD')
>> "2017-07-31"
The Moment.js code calls new Date() to initialize itself when the constructor is called without arguments (technically, it calls new Date(Date.now()), but the result is the same). You have to pass something to get a specific date.
Of course, you could alter your local copy of the Moment.js library, but this is not recommended. You would have to keep it up-to-date with later releases of the libraries. And causing moment() to return anything other than the current date would cause those looking back at your code to wonder what's going on.
Upon further investigation, it seems Moment.js does allow you to overwrite the implementation of moment.now() which tells the rest of the library what time it is. See this article on the Moment.js website for more. There's an example there:
moment.now = function () {
return +new Date();
}
Which would be easy to alter for your needs:
moment.now = function () {
return +new Date(2017, 2, 1); // March 1st, 2017
}
I would strongly suggest using this technique sparingly (if at all) for the reasons given in the second paragraph above.

Date presentation with AngularJS - how costly is a filter?

I think the angular date and currency filters are really slick, but I've read some commentary online saying that filters negatively impact performance. I'm working on an enterprise app that will be handling all different types of date objects, and we want to render the formatting differently based on user settings.
Based on what I've read, using the filter directly in the DOM is not the best approach, so I'm thinking I'll extract it to a service. The angular documentation leaves so much to be desired, as you know, and there seem to be a lot of different ways to accomplish this.
Ultimately I just want to use angular's built in date filter for presenting a variety of date formats coming from payloads on various pages to format that date. Furthermore, we have independent user settings for both date and time. The options for date formatting are: MM/dd/yyyy and dd/MM/yyyy. The options for time formatting are: HH:MM:SS and H:MM:SS A
I am leaning toward using the built in date filter in a service. I think the ideal answer would just need to contain a bit of pseudocode to get me going. Thanks in advance for your time.
Also - please let me know if you need more info or any code. Not sure what to include here...
I figured out what I was doing wrong with my first attempt. In case anyone else is looking for this topic, here's the code:
app.service('DateTimeService', ['$filter', function ($filter) {
var self = this
init()
return self
function init () {
self.formatter = $filter('date')
self.formatDate = formatDate
self.formatTime = formatTime
}
function formatDate (time) {
return self.formatter(time, settings.dateFormat)
}
function formatTime (date) {
return self.formatter(date, settings.timeFormat)
}
}])
// in the controller
DateTimeService.formatDate(dateObject)

Save the actual date in a variable (only date, no time)

I want to save the actual date in a variable. only the date, no time
var a = #Date(#Now());
datasource.replaceItemValue("variable", a)`
And
var a = #Date(#Now());
var b = new Date(a.getYear(), a.getMonth(), a.getDay());
datasource.replaceItemValue("variable", b)
Are returning 28.10.14 00:00
var dt:NotesDateTime = #Date(#Now());
datasource.replaceItemValue("variable", dt.getDateOnly());
Is throwing me an error
Isn't there a simple way to get only the actual date without the time?
Use setAnyTime() metohd of NotesDateTime class to remove time component.
If you want to save only the date use a textfield and convert the text to date, if you need it in your code
#Now uses a java.util.Date, which includes time portions. .getDateOnly() is probably throwing an error because that returns a String.
The underlying session.createDateTime() method accepts either text, a java.util.Date or a java.util.Calendar. I think all of them need to include a time element.
If you're only storing the value for reference, I'd agree with brso05 to not worry.
If you're ever likely to use #Adjust (or an equivalent), then not worrying about the time is a recipe for disaster, because every time you try to adjust, you need to remember to take into account Daylight Savings Time.
One option is to set the time to 12:00 midday. That means DST will not be a problem.
java.sql.Date is specifically designed to only include the Date portion, without a time element. Jesse Gallagher talks about java.sql.Date in the context of his frostillic.us framework https://frostillic.us/f.nsf/posts/32A63DD640D868D885257D18006659A9 and he was the one I found out about java.sql.Date from. I'm not sure how he stores those values though.
I'm not sure if the OpenNTF Domino API will allow you to just pass a java.sql.Date to a field and so store just the date portion.

Show date with format

I have:
var date = new Date();
and i have many formats:
var one = 'yy-mm-dd';
var two = 'dd.mm.yy';
var three = 'dd/mm/yy';
var four = 'mm/dd/yy';
Is possible to showing current date with this four formats? I know - i can use clause IF or SWITCH and set this, but maybe in JavaScript or jQuery without external libraries i can use this format as option?
If you're also already using jQuery UI, there's a string formatter function in the DatePicker.
If not, use Datejs.
You will have to do it yourself by using getFullYear(), getMonth() and getDate() and combining them as you see fit (no jquery/jquery UI required).
If you are using or can use JQuery UI you can take advantage of the $.datepicker.formatDate method (that's the approach we took).
Your question has been asked (in a somehow different form) before

Categories

Resources