NodeJS (JavaScript) - Fastest method to convert date? - javascript

In NodeJS, I'm reading and parsing a .txt file with more than 1.5M lines. Each line is in the format: date,number,number, where each date is yyyyMMddhhmmss. An example line is:
20170506014255,100.01,200.02
Using jFile, I can read and parse all 1.5M+ lines in about 2 seconds...
var jFile = require('jfile');
var data = [];
var dataFile = new jFile('./dataFile.txt');
dataFile.lines.forEach(function(line) {
data.push(line.split(','));
});
Works great! But, I'd like to change the date format to something else. For this, I am using date-format to do the conversion...
... same as previous, with new line within forEach() ...
var dateFormatter = require('date-format');
dataFile.lines.forEach(function(line) {
let tdata = line.split(',');
tdata[0] = dateFormatter('MM/dd/yy hh:mm:ss', dateFormatter.parse('yyyyMMddhhmmss', tdata[0]));
data.push(tdata);
});
Again, this works great! Mostly. What once took only 2 seconds now takes about 25 seconds. Gasp!
Ideally, the file would just have the dates formatted the correct way, but this is out of my hands.
Is there a faster way to do this conversion? Maybe there is a more native approach, or just a faster package?
Thanks for any insight!

I guess it is faster to hardcode the parsing:
function fixFormat(date) {
const yy = date.slice(2, 4);
const MM = date.slice(4, 6);
const dd = date.slice(6, 8);
const hh = date.slice(8, 10);
const mm = date.slice(10, 12);
const ss = date.slice(12, 14);
return `${MM}/${dd}/${yy} ${hh}:${mm}:${ss}`;
}
Or really really ugly:
const y = 2, M = 4, d = 6, h = 8, m = 10, s = 12;
const pattern = fn => date => fn(p => date[p] + date[p + 1])
const fixFormat = pattern(p => p(M) + "/" + p(d) + "/" + p(y) + " " + p(h) + ":" + p(m) + ":" + p(s));

It seems you want to play a game of coding golf to see who can write the fastest code for you.
Anything that parses the string, creates a Date, then generates a string from if it going to be slower than something that just reformats the string. Jonas' approach is valid, and probably fast enough, but all those slices must take their toll. A single match should be faster, but it's up to you:
// Convert a timestamp in yyyyMMddhhmmss format to MM/dd/yy hh:mm:ss
// where "hh" is assumed to be 24 hr
function formatDate(s) {
var b = s.match(/\d\d/g);
return `${b[2]}/${b[3]}/${b[1]} ${b[4]}:${b[5]}:${b[6]}`;
}
console.log(formatDate('20170506014255'));
I have no idea if that's faster, but it's certainly a lot less code. If you really want to make it fast, create the regular expression once:
// Convert a timestamp in yyyyMMddhhmmss format to MM/dd/yy hh:mm:ss
// where "hh" is assumed to be 24 hr
var formatDate = (function() {
var re = /\d\d/g;
return function (s) {
var b = s.match(re);
return `${b[2]}/${b[3]}/${b[1]} ${b[4]}:${b[5]}:${b[6]}`;
};
}());
console.log(formatDate('20170506014255'));

Related

Difficulties with numeric date offset in luxon

Environment: Win 10 Pro, Chrome 85, luxon 1.25.0
What I am trying to achieve eventually is this: in an ASP.Net/c# application show to the user continuously the amount of time until a session time out will occur. Because server and client may be in different time zones I need the UTC offset of each. The client's offset is easy to get. To find the server's offset (with reference to the code snippet below): the server code puts the page last loaded time into lblLastLoaded. Object dto receives the parsed date parts, including dto.offset which, I gather, is supposed to be expressed in minutes. The subsequent call to luxon.DateTime.fromObject(dto) fails: pst is left undefined. When I do not set dto.offset (by commenting out 4 lines in the code below) pst gets the server time successfully, but without the offset; it appears that luxon uses the offset of my local system which is -7 hours.
<script>
function r4onload() {
// Get server time:
var st = document.getElementById('lblLastLoaded').innerHTML;
// Date Time Offset
// st has form YYYY/MM/dd HH:mm:ss -HH:mm
// 1 2
// 012345678901234567890123456
// For Example 2020/09/29 10:31:56 -07:00
let dto = {};
dto.year = Number(st.substring(0, 4));
dto.month = Number(st.substring(5, 7));
dto.day = Number(st.substring(8, 10));
dto.hour = Number(st.substring(11, 13));
dto.minute = Number(st.substring(14, 16));
var offsetHour = Number(st.substring(20, 23)); // works if these 4 lines are commented out
var offsetMinutes = Number(st.substring(24, 26)); // works if these 4 lines are commented out
dto.offset = offsetHour * 60 + Math.sign(offsetHour) * offsetMinutes; // works if these 4 lines are commented out
// dto.offset is correctly calculated to -420 minutes // works if these 4 lines are commented out
var pst = luxon.DateTime.fromObject(dto);
// pst is undefined at this point -- why??
// If I do not include anything about offset above (comment out the 4 lines
// containing offsetHours, offsetMinutes, and dto.Offset, then pst comes out like this:
// 2020-09-29T10:31:00.00000-07:00
// i.e., luxon used the offset -07:00 of my local system, not the one contained in variable st.
document.getElementById('Parsed').innerHTML = pst;
r4startTime();
}
function r4startTime() {
var dt = luxon.DateTime.local();
var h = dt.hour;
var m = dt.minute;
var s = dt.second;
m = r4checkTime(m);
s = r4checkTime(s);
document.getElementById('CurrTime').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(r4startTime, 2000);
}
function r4checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
A complete Visual Studio 2017 project DemoLuxon with the above code snippet in file Site.Master is here: https://1drv.ms/u/s!AvoFL8QrGVaTsQvbaB8-Zh7GdloV?e=ODjZW5
If the above approach is awkward, I would be grateful for suggestions of more elegant ways of determining the client/server offset difference.
I devised a workaround as follows below, but the original problem has not been answered:
<script>
function r4onload() {
var st = document.getElementById('lblLastLoaded').innerHTML;
// Date Time Offset
// st has form YYYY/MM/dd HH:mm:ss -HH:mm
// 1 2
// 012345678901234567890123456
// For Example 2020/09/29 10:31:56 -07:00
// Transform to ISO format:
st = st.substring(0, 4) + '-' + st.substring(5, 7) + '-' + st.substring(8, 10)
+ 'T' + st.substring(11, 19) + ".000" + st.substring(20);
document.getElementById('Xformed').innerHTML = st;
var pst = luxon.DateTime.fromISO(st, { setZone: true });
document.getElementById('Parsed').innerHTML = pst;
r4startTime();
}
function r4startTime() {
var dt = luxon.DateTime.local();
var h = dt.hour;
var m = dt.minute;
var s = dt.second;
m = r4checkTime(m);
s = r4checkTime(s);
document.getElementById('CurrTime').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(r4startTime, 2000);
}
function r4checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
i.e., put the date-time first into ISO format and then use luxon.DateTime.fromISO. Variable pst gets the correct date-time value including the offset. The problem with luxon.DateTime.fromObject with an offset remains unresolved.

Angular: how to convert time from 00:00:01 to 8 min 49 second format?

I want to convert time from 00:00:01 (which is not a date object) to 8 min 49 second format.
I went through Angular 'date pipe' documentation also but I didn't get any solution.
Angular date pipes is the way to go... This should work for you in your HTML:
Update:
from your comments, i gather that you have a time string, due to which you'd first have to convert that time string into a date... after that, the Angular Date pipe will handle the rest;
relevant TS:
priyankaTime = '08:04:01';
priyankaDate;
constructor() {
this.priyankaFunction()
}
priyankaFunction() {
var origStr = this.priyankaTime;
var n = origStr.search(":");
var hrPart = origStr.substring(0, n);
var str = origStr.substring(n + 1, origStr.length);
var n = str.search(":");
var minPart = str.substring(0, 2);
var str = str.substring(n + 1, str.length);
var n = str.search(":");
var secPart = str.substring(0, 2);
console.log(hrPart, ':', minPart, ':', secPart);
this.priyankaDate = new Date();
this.priyankaDate.setHours(hrPart, minPart, secPart);
}
relevant HTML:
{{myDateVariable | date:"h 'hours' mm 'minutes' ss 'seconds'" }}
check updated working stackblitz here

Javascript number like time regex format

I'm receiving from my database time like hh:mm:ss, and in javascript i would like to put the time like hh:mm
this is my code
var time = '10:01:30';
console.log(time);
var res = formatTime(time);
console.log(res);
function formatTime(time) {
var result = false, m;
var re = /^\s*([01]?\d|2[0-3]):?([0-5]\d)\s*$/;
if ((m = time.match(re))) {
result = (m[1].length === 2 ? "" : "0") + m[1] + ":" + m[2];
console.log(result);
}
}
The function doesn't work well since i receive "false", any help?
Thanks
May be I am missing something in the question, but if you simply want to extract the hh:mm part from hh:mm:ss, then this should work:
// var time = "hh:mm:ss";
var time = "10:01:30";
var splitTime = time.trim().split(":"); // trim to remove any leading and trailing spaces
var formattedTime = splitTime[0] +":"+ splitTime[1];
console.log( formattedTime );
Couldn't you just do the following?:
function formatTime(time) {
var array = time.split(':');
return array[0] + ':' + array[1];
}
The other answer (using split) is undoubtably the easier way to do this.
However, if you're wondering why your regex was not matching, it is because your regular expression was looking for the first (hh) block, and then the second (mm) block, but was then expecting whitespace after that until the end of the line - no allowance for the ss part.
I changed this rather heavy-handedly to allow anything after the mm part until the end of the line. see below.
Also, if you're wondering why your formatTime function returns undefined its because you forgot to return result
var time = '10:01:30';
console.log(time);
var res = formatTime(time);
console.log(res);
function formatTime(time) {
var result = false, m;
var re = /^\s*([01]?\d|2[0-3]):?([0-5]\d).*$/;
if ((m = time.match(re))) {
result = (m[1].length === 2 ? "" : "0") + m[1] + ":" + m[2];
console.log(result);
}
return result;
}
I would consider working with native Date object to do your formatting. This will do a few things for you:
Automatically validate the time value that is being input. No need for regex to do this. Either the input string is valid and the function works, or it is invalid and the function returns NaN.
Give you flexibility in how you work with the value. Need to convert time zones, convert to Unix timestamp, etc.? These are built in methods on Date object.
Gives flexibility on input values. You could potentially you other string input types here if needed as long as they can allow for instantiation of valid Date object. You need to modify regex to allow for multiple input types or anything like that.
Using this approach, example code might look like:
function stripSecondsFromTimeString(time) {
// create data object representing current date
// the date is not really important here other than allowing
// you to format a fully valid Date object with your time fragment
var day = new Date();
var dateInput = day.toDateString() + ' ' + time;
var date = new Date(dateInput);
// validate we were able to get useful Date object
if(isNaN(date.getHours())) {
return NaN;
}
// log out some values so you can see how you might more fully work with Date object
console.log(date.toString());
console.log(date.getDate());
console.log(date.getHours());
console.log(date.getMinutes());
// prepare to return string
var hours = '' + date.getHours();
if(hours.length === 1) {
hours = '0' + hours;
}
var minutes = '' + date.getMinutes();
if(minutes.length === 1) {
minutes = '0' + minutes;
}
return hours + ':' + minutes;
}
// Usage examples
// your input time fragment
var inputTime = '10:01:30';
var formattedTime = stripSecondsFromTimeString(inputTime);
console.log(formattedTime);
// example failure case
var invalidTime = 'foo';
console.log(stripSecondsFromTimeString(invalidTime));

My substr method not working in js

What is the difference between the uncommented lines vs the commented(which is grabbing mm and multiplying by 60 then concatenating with ss)?
function getSeconds(str) {
// var mm = str.substr(0,2);
// var ss = str.substr(3,5);
// return mm*60+ss;
var nums = str.split(':'),
mm = +nums[0],
ss = +nums[1];
return mm * 60 + ss;
}
getSeconds("13:25");
In the working example, you are explicitly converting the strings into numbers using the + prefix.
In the commented out example, you are not. The minutes are implicitly converted into a number due to the multiplication, however the seconds are simply appended via a string concatenation.
You can resolve that by explicitly converting the two components this example as well:
function getSeconds(str) {
var mm = +str.substr(0,2);
var ss = +str.substr(3,2);
return mm*60+ss;
}
console.log(getSeconds("13:25"));
You need to convert to string before using .substring();
var myStr = value.toString().substring(2,4);

JavaScript Time Until

I need to do the simplest thing, take an input date/time and write out the hours:minutes:seconds until that time. I haven't been able to figure it out. I even tried using Datejs which is great, but doesn't seem to have this functionality built in.
The time is going to be somewhere in the range of 0 mins -> 20 minutes
Thanks!
Don't bother with a library for something so simple. You must know the format of the input date string whether you use a library or not, so presuming ISO8601 (like 2013-02-08T08:34:15Z) you can do something like:
// Convert string in ISO8601 format to date object
// e.g. 2013-02-08T02:40:00Z
//
function isoToObj(s) {
var b = s.split(/[-TZ:]/i);
return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5]));
}
function timeToGo(s) {
// Utility to add leading zero
function z(n) {
return (n < 10? '0' : '') + n;
}
// Convert string to date object
var d = isoToObj(s);
var diff = d - new Date();
// Allow for previous times
var sign = diff < 0? '-' : '';
diff = Math.abs(diff);
// Get time components
var hours = diff/3.6e6 | 0;
var mins = diff%3.6e6 / 6e4 | 0;
var secs = Math.round(diff%6e4 / 1e3);
// Return formatted string
return sign + z(hours) + ':' + z(mins) + ':' + z(secs);
}
You may need to play with the function that converts the string to a date, but not much. You should be providing a UTC timestring anyway, unless you can be certain that the local time of the client is set to the timezone of the supplied datetime value.
Instead of Date.js, try Moment.js.

Categories

Resources