positioning entries on a timeline - javascript

Hello I have calender/schedule in an app that looks similar to this very basic example,
| Jan | Feb | Mar | Apr | Jun | Jul | Aug | Sep | Oct | Nov | Dec |
Project #1 (Runs from start of Jan to mid March) ...............
Project #2 (Runs from mid march to early september)
..............................
The dots under the project title illustrate the length of the project, what I am struggling with is giving the entry the correct value of left margin to push the project to the correct start date.
The figures I have available to me are:
Number of days the projects run,
Number of days between the 01/01/2014 and the first days of the project.
Total number of days in the calendar (the calendar runs Jan 2014 - Dec 2019).
Width of the container holding the calendar.
I thought it would be something like this:
var remainder = number_of_days_in_calendar - this.model.get('num_days_from_year_start');
var decimal = remainder / number_of_days_in_calendar;
var marginLeft = decimal * 100 + "%";
But this returns percentages far too close together there is barely any difference between, Jan and August.
I have worked out the project length successful using this sum,
var width = (parseInt(this.model.get('run_number_days')) / number_of_days_in_calendar) * 100;
this.$el.width(width + "%");
But nothing similar works for positioning the projects.

Calculate the margin based on the total width of the calendar on screen.
width = calendar width in pixels * decimal
If I understand correctly decimal in your calculation is the percentage of days before the project start to the total number of days in the calendar.

Let's say we have these values
number_of_days_in_calendar = 365
day_when_project_started = 91
container_width = 365px
this is how we could calculate the position of left margin
((91 / 365) * 100) * (365px / 365) = margin-left: 24.93%
If the container is, for instance 730px wide, according to the formula above, the final result would be margin-left: 49.86%;

Related

date-fns get duration in hh:mm format (minutes in 100 unit based)

I'm build a time logging utilities for myself as a project to get better with vuejs and JavaScript. user can enter multiple task entries. Each task consist of:
start (as a time picker) {return a Date object} [task.start]
end (as a time picker) {return a Date object} [task.end]
other fields...
What I want to do when I display my list of task, is to show the duration of the task on the format of hh:ss.
hh = the number of hours 0 to infinite (can go over 24 hours, like 26)
ss = the number of minutes on a base of 100. Example, 15 minutes = 25
Final output would like this:
start / end / result
November 17th, 2022 08:00 / November 17th, 2022 09:15 / 1:25
November 17th, 2022 08:00 / November 17th, 2022 11:45 / 3:75
November 17th, 2022 08:00 / November 17th, 2022 8:30 / 0:50
November 17th, 2022 08:00 / November 18th, 2022 11:00 / 27:00
I have succeeded to get that result, but I don't think the way i did it is efficient / the best way:
import { differenceInSeconds, intervalToDuration } from "date-fns";
const zeroPad = (num) => String(num).padStart(2, '0');
const getDuration = (task) => {
const rawDuration = intervalToDuration({start: 0, end: differenceInSeconds(task.end, task.start) * 1000});
return `${rawDuration.hours}:${zeroPad((rawDuration.minutes/60)*100)}`;
};
I would like like to use date-fns library on this project since it is smaller than moment.js and I already use it for other date manipulation. But I am willing to switch over to moment.js if needed. I would be also open to vanilla js if it do not need much more code.
I will continue to try to find a solution on my end, I will update this post if I find anything better than what I have done.
Thanks.

Date difference calculation in C# vs Moment.js

I was doing calculation on two dates. I need to find how much days left for the user to use their contract in the site. I have expiry date stored in the DB. And I need to compare this with the current date and get the remaining days left to enjoy their subscription.
Initially this number of days remaining calculation was in the C#.
var daysLeft = Convert.ToInt32((data.expiryDate.Date - DateTime.Now.Date).TotalDays);
//Say, the expiryDate is Thu Dec 31 2020 00:00:00 GMT+0530 (India Standard Time), And daysLeft is 220 for the above statement
And Now i tried the same in Moment.js in client side.
moment(data.expiryDate).diff(moment(), 'days')
//Say, the expiryDate is Thu Dec 31 2020 00:00:00 GMT+0530 (India Standard Time) and it is giving 219.
I also tried like subtracting two dates in same format after converting it to YYYY-DD-MM as below which is giving the error
moment(data.expiryDate).format('YYYY-DD-MM').diff(moment().format('YYYY-DD-MM'), 'days')
Object doesn't support property or method 'diff'
Why in C# its 220 and in moment.js it is 219? Am I missing anything? Please suggest me where the calculation goes wrong.
When you do this in c#:
data.expiryDate.Date - DateTime.Now.Date
you actually substract whole days (because .Date results in time being 00:00:00.000).
Now, you do the Following in js:
moment(data.expiryDate).diff(moment(), 'days')
and the difference here is that you substract date & time.
Note (use of .Now without .Date):
var expiryDate = DateTime.Parse("12/31/2020 10:00:00");
Console.WriteLine((expiryDate.Date - DateTime.Now).TotalDays);
returns 219.654703995023 when the same code with .Date returns 220
TL;DR:
---------------------------------------------------------------
| moment.js | C# |
---------------------------------------------------------------
|moment() | DateTime.Now |
|moment().startOf('day')| DateTime.Today (=DateTime.Now.Date) |
---------------------------------------------------------------
If you want the same result for your javascript part, you should probably use .startOf('day') (which seems to be the equivalent of .Date according to Moment.js | Home)
In C#, TotalDays represents whole and fractional days, the return type is double. And convert to int will round to the nearest 32-bit signed integer.
In moment.js, diff will truncate the result to zero decimal places, returning an integer.
But before 2.0.0, diff returned a number rounded to the nearest integer, not a truncated number.

Using time as an coordinate in nvD3 plots

I am trying to plot an array of values on a line plot. The values each have a date/time stamp.
So an example data point is:
aPoint = { 'label': 201401082015, //so this corresponds to 2014, Jan 08th, at 10:15PM
'data' : 1234
};
How do I convert label into a form that nvd3 can recognise as a date/time? By not changing the form of label, incorrect spacing between data points will occur (due to 60 minutes in 1 hour, 24 hours in 1 day and not 100).
To elaborate, if an event occurs at 23:00 hrs (11pm), and another at 01:00 hrs (1am) the following day, then in reality these events are 2 hours apart. Incorrectly however, they will be plotted as if they are 78 hours (101-23=78) apart due to hours in a day not being base 10.
How do I convert label into a form that nvd3 can recognise as a date/time?
How do I convert label into a form that nvd3 can recognize as a
date/time?
Like this:
function labelToMs(label){
var parts = label.toString().match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})$/);
var partsToInt = parts.slice(0,5).map(function(s){return parseInt(s)});
var date = new Date(partsToInt[0], partsToInt[1]-1, partsToInt[2], partsToInt[3], partsToInt[4]);
return date.getTime();
}
This function will return a number that won't have that issue, because it will be the number of milliseconds since 1 January 1970 00:00:00 UTC.
Also, if you have an Array of points and you want to convert it to an Array with the label as the number of MS, you could do it like this:
var yourArrayOfPoints = yourArrayOfPoints.map(function(point){
point.label = labelToMs(point.label);
return point;
});

Javascript equivalent of visual foxpro gomonth()

I'm tasked with writing a web portal for a legacy application that was written in Visual Foxpro. I have to validate a pregnancy due date. The rule is that it can't be more than 9 months from the current date. I've already tried to argue that this is too vague and that it needs to be in days or weeks, but I was told that I have to mimic the legacy software.
Here's what the code in VSP is doing:
maxValueForDueDate = GOMONTH(DATE() , 9)
According to MSDN GOMONTH() handles edge cases as follows:
SET CENTURY ON
STORE GOMONTH({^1998-02-16}, 5) TO gdDeadLine
CLEAR
? gdDeadLine && Displays 07/16/1998
? GOMONTH({^1998-12-31}, 2) && Displays 02/28/1999
? GOMONTH({^1998-12-31}, -2) && Displays 10/31/1998
As you can see adding 2 months to December 31st does not result in March 2nd, unfortunately that's exactly what the following javascript does:
var dDate = new Date('1998-12-31');
dDate.setMonth(dDate.getMonth() + 2);
alert(dDate.toDateString()); // results in - Tue Mar 02 1999
Does anyone have a javascript function handy that they've written for this scenario? I've googled around, but haven't found what I need. I'm limited in my third-party usage to JQuery.
Add the number of milliseconds (or seconds or hours or days) in 2 "full months" (that is, 30 days x 24 hours). The idea is that the entire date is shifted, and not just the single [month] component. For example:
var a = new Date('1998-12-31')
var ms_in_month = 30 * (24 * 60 * 60) * 1000
var b_ticks = (+a) + 2 * ms_in_month
var b = new Date(b_ticks)
alert(b) // Sun Feb 28 1999 16:00:00 GMT-0800 (Pacific Standard Time)
The (+a) coerces the Date to a number which results in the number of milliseconds since epoch. (This could also be written as a.milliseconds). Then new Date(millis_since_epoch) does the reverse and creates a Date from the epoch offset.
Disclaimer: I am not sure what the exact rules for GOMONTH are
, and it might use the "30.5 days in a month heuristic" (365/12 = 30.41) or another variation. I suspect it does not account for the month durations (the documentation does state that "-1 [month] means -31 days") or leap years ..
You can look at the open source javascript date library Datejs
If you cannot add this file, you can at least look at the code to see how the edge cases are handled.

Calculating Jday(Julian Day) in javascript

I have requirement to calculate jday in javascript , for doing client side validation , Can any one help me how to calculate JDAY in javascript or script to change given JDAY to actual date or vice versa .
To know what is JDay ,I found the following site ,
http://www.pauahtun.org/Software/jday.1.html
Am also refering the below site for calculation which is mentioned in JAVA
http://www.rgagnon.com/javadetails/java-0506.html
Thank you in advance
Julian Day
The Julian Day is the number of elapsed days since the beginning of a cycle of 7980 years.
Invented in 1583 by Joseph Scaliger, the purpose of the system is to make it easy to compute an integer (whole number) difference between one calendar date and another calendar date.
The 7980 year cycle was derived by combining several traditional time cycles (solar, lunar, and a particular Roman tax cycle) for which 7980 was a common multiple.
The starting point for the first Julian cycle began on January 1, 4713 B.C. at noon GMT, and will end on January 22, 3268 at noon GMT, exactly 7980 whole days later.
As an example, the Julian day number for January 1, 2016 was 2,457,389, which is the number of days since January 1, 4713 B.C. at that day.
How to calculate it
As we know that Unix time is the number of seconds since 00:00:00 UTC, January 1, 1970, not counting leap seconds, and also called Epoch, we can use some math to calculate the Julian Day when we already have the Unix time.
GMT and UTC share the same current time in practice, so for this, there should be no difference.
To start with, we need to know the number of days from when the Julian cycle began, until Unix timestamps began.
In other words, the number of days from January 1, 4713 B.C. at 12:00:00 GMT, until January 1, 1970 at 00:00:00 UTC.
Having this set number of days, that never change, we can just add the number of days from January 1, 1970 until today, which is what Javascript returns anyway, to get the Julian Day.
Without adding up all those years, but simply by searching the web, it tells us that the difference in days between the year 4713 B.C. and 1970 A.D. is 2440588 days, and because the Julian Cycle began at noon, not at midnight, we have to subtract exactly half a day, making it 2440587.5 days.
So what we have now is 2440587.5 days + UNIX TIME in days === Julian Day
With some simple math we can figure out that a day is 86,400 seconds long, and the Unix timestamp is in milliseconds when using Javascript, so UNIX TIME / 86400000 would get us the number of days since Thursday, 1 January 1970, until today.
Now for just the day, we wanted the whole number of days, and not the fractional, and can just round it down to the closes whole day, doing something like
Math.floor((UNIX TIME / 86400000) + 2440587.5);
Julian Date
Sometimes in programming, a "Julian Date" has come to mean the number of days since the year started, for instance June 1, 2016 would be 152 days into that year etc.
The correct use of "Julian Date" is a Julian Day with a timestamp added as a fractional part of the day.
Taking the example at the top of this answer, where January 1, 2016 was the Julian Day 2,457,389 , we can add a time to that.
The Julian Day starts at noon, with no fractional time added, and so at midnight it would be 2457389.5 and at 18:00, or six hours after noon, it would be 2457389.25, adding "half a day", "quarter of a day" etc.
Calculating it, again
This means 0.1 Julian Date is the same as 24 hours divided by 10, or 24 / 10 === 2.4 hours, or in other words, Julian Day timestamps are fractional with decimals (one tenth of a day etc).
Lets look at some Javascript functions, firstly the Date constructor.
Javascript only has access to the local time on the computer it runs on, so when we do new Date() it does not neccessarely create an UTC date, even if UNIX time is in UTC, new Date gives you the number of seconds from epoch until whatever local time your computer has, and does not take your timezone into consideration.
Javascript does however have Date.UTC, which would return the date in UTC format, lets check the difference, and this will of course differ according to the timezone you've set the local system to.
var regular_date = new Date(2016, 1, 1, 0, 0, 0);
var UTC_date = Date.UTC(2016, 1, 1, 0, 0, 0);
var difference = UTC_date - regular_date;
document.body.innerHTML = 'The difference between your local time and UTC is ' +(difference/1000)+ ' seconds';
Remember the part at the begin of this chapter, about 0.1 Julian Date being the same as 24 hours divided by 10, or 24 / 10 === 2.4 hours, well, 2.4 hours is 144 minutes, and now lets look quickly at Javascripts getTimezoneOffset() method, the docs say
The getTimezoneOffset() method returns the time-zone offset from UTC,
in minutes, for the current locale.
So, it returns the offset for the systems timezone in minutes, that's interesting as most javascript methods that deal with dates returns milliseconds.
We know that a 1/10 of a day is 144 minutes, so 10/10, or a whole day, would be 1440 minutes, so we could use some math to counteract the local systems timezone, given in minutes, and divide it by the number of minutes in a day, to get the correct fractional value
So now we have
2440587.5 days + UNIX TIME in days === Julian Day
and we know Javascripts Date constructor doesn't really use UTC for the current date, but the system time, so we have to have
TIMEZONEOFFSET / 1440
joining them together we would get
(JAVASCRIPT TIME / 86400000) - (TIMEZONEOFFSET / 1440) + 2440587.5
// ^^ days since epoch ^^ ^^ subtract offset ^^ ^^days from 4713 B.C. to 1970 A.D.
Translating that to javascript would be
var date = new Date(); // a new date
var time = date.getTime(); // the timestamp, not neccessarely using UTC as current time
var julian_day = (time / 86400000) - (date.getTimezoneOffset()/1440) + 2440587.5);
Now this is what we should use to get the Julian Day as well, taking measures to remove the timezone offset, and of course without the fractional time part of the Julian Date.
We would do this by simpy rounding it down to the closest whole integer
var julian_date = Math.floor((time / 86400000) - (date.getTimezoneOffset()/1440) + 2440587.5));
And it's time for my original answer to this question, before I made this extremely long edit to explain why this is the correct approach, after complaints in the comment field.
Date.prototype.getJulian = function() {
return Math.floor((this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5);
}
var today = new Date(); //set any date
var julian = today.getJulian(); //get Julian counterpart
console.log(julian)
.as-console-wrapper {top:0}
And the same with the fracional part
Date.prototype.getJulian = function() {
return (this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5;
}
var today = new Date(); //set any date
var julian = today.getJulian(); //get Julian counterpart
console.log(julian)
.as-console-wrapper { top: 0 }
And to finish of, an example showing why
new Date().getTime()/86400000 + 2440587.5
doesn't work, at least not if your system time is set to a timezone with an offset, i.e. anything other than GMT
// the correct approach
Date.prototype.getJulian = function() {
return (this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5;
}
// the simple approach, that does not take the timezone into consideration
Date.prototype.notReallyJulian = function() {
return this.getTime()/86400000 + 2440587.5;
}
// --------------
// remember how 18:00 should return a fractional 0.25 etc
var date = new Date(2016, 0, 1, 18, 0, 0, 0);
// ^ ^ ^ ^ ^ ^ ^
// year month date hour min sec milli
var julian = date.getJulian(); //get Julian date
var maybe = date.notReallyJulian(); // not so much
console.log(julian); // always returns 2457389.25
console.log(maybe); // returns different fractions, depending on timezone offset
.as-console-wrapper { top: 0 }
new Date().getTime()/86400000 + 2440587.5
will get the unix time stamp, convert it to days and add the JD of 1970-01-01, which is the epoch of the unix time stamp.
This is what astronomers call julian date. It is well defined. Since neither Unix time stamp nor JD take leap seconds into account that does not reduce the accuracy. Note that JD need not be in timezone UTC (but usually is). This answer gives you the JD in timezone UTC.
According to wikipedia:
a = (14 - month) / 12
y = year + 4800 - a
m = month + 12a - 3
JDN = day + (153m + 2) / 5 + 365y + y/4 - y/100 + y/400 - 32045
If you're having a more specific problem with the implementation, provide those details in the question so we can help further.
NOTE : This is not correct because the "floor brackets" on Wiki were forgotten here.
The correct formulas are:
a = Int((14 - Month) / 12)
y = Year + 4800 - a
m = Month + 12 * a - 3
JDN = Day + Int((153 * m + 2) / 5) + 365 * y + Int(y / 4) - Int(y / 100) + Int(y / 400) - 32045
JD =>
const millisecondsSince1970Now = new Date+0
const julianDayNow = 2440587.5+new Date/864e5
const dateNow = new Date((julianDayNow-2440587.5)*864e5)
There seems to be confusion about what a Julian-Day is, and how to calculate one.
Javascript time is measured as GMT/UTC milliseconds UInt64 from Jan 1, 1970 at midnight.
The Month, Day, Year aspects of the JavaScript Date function are all implemented using Gregorian Calendar rules. But Julian "Days" are unaffected by that; however mapping a "day-count" to a Julian Month, Day, Year would be.
Calculating Julian-Day conversions are therefore a relative day count from that point in time (Jan 1, 1970 GMT/UTC Gregorian).
The Julian-Day for Jan 1, 1970 is 2440587.5 (0.5 because JulianDays started at NOON).
The 864e5 constant is JavaScript notation for 86,400,000 (milliseconds/day).
The only complexities are in calculating Julian dates (days) prior to adoption of the 1582 Gregorian calendar whose changes mandated from Pope Gregory were to correct for Leap Year drift inaccuracies affecting Easter. It took until around 1752 to be fully adopted throughout most countries in the world which were using the Julian Calendar system or a derivative (Russia and China took until the 20th century).
And the more egregious errors in the first 60 years of Julian date implementation from Julius Caesar's 46BC "reform" mandate where priests made mistakes and people misunderstood as they folded a 14/15 month calendar. (hence errors in many religious dates and times of that period).
🎪 None of which applies in JavaScript computation of Julian Day values.
See also: (from AfEE EdgeS/EdgeShell scripting core notes)
Astronomy Answers - Julian Day Number (multi-calendrical conversions)
Julian calendar
Atomic Clocks
JavaScript operator precedence
Microsoft FILETIME relative to 1/1/1601 epoch units: 10^-7 (100ns)
UUID/GUIDs timestamp formats - useful for time-date conversion also
"Leap Second" details
There is a separate subtlety "leap-second" which applies to astronomical calculations and the use of atomic clocks that has to do with earth orbital path and rotational drift.
i.e., 86,400.000 seconds per day needs "adjustment" to keep calendars (TimeZones, GPS satellites) in sync as it is currently 86,400.002.
It seems that the final code given in the accepted answer is wrong. Check the "official" online calculator at US Naval Observarory website:
http://aa.usno.navy.mil/data/docs/JulianDate.php
If someone knows the correct answer to a answer time and calendar, it's USNO.
Additionally, there is an npm package for this:
julian
Convert between Date object and Julian dates used in astronomy and history
var julian = require('julian');
var now = new Date(); // Let's say it's Thu, 21 Nov 2013 10:47:02 GMT
var jd = '';
console.log(jd = julian(now)); // -> '2456617.949335'
console.log(julian.toDate(jd)); // -> Timestamp above in local TZ
https://www.npmjs.com/package/julian
Whatever you do, DON'T USE getTimezoneOffset() on dates before a change of policy in the current Locale, it's completely broken in the past (it doesn't apply iana database rules).
For example, if I enter (UTC date 1st of october 1995 at 00:00:00):
var d=new Date(Date.UTC(1995, 9, 1, 0, 0, 0)); console.log(d.toLocaleString()); console.log(d.getTimezoneOffset());
in the javascript console in Chrome, it prints (I'm in France):
01/10/1995 at 01:00:00 <= this is winter time, +1:00 from UTC
-120 <= BUT this is summer time offset (should be -60 for winter)
Between 1973 and 1995 (included), DST (-120) terminated last Sunday of September, hence for 1st of October 1995, getTimezoneOffset() should return -60, not -120. Note that the formatted date is right (01:00:00 is the expected -60).
Same result in Firefox, but in IE and Edge, it's worse, even the formatted date is wrong (01‎/‎10‎/‎1995‎ ‎02‎:‎00‎:‎00, matching the bad -120 result of getTimezoneOffset()). Whatever the browser (of these 4), getTimezoneOffset() uses the current rules rather than those of the considered date.
Variation on the same problem when DST didn't applied in France (1946-1975), Chrome console:
d=new Date(Date.UTC(1970, 6, 1, 0, 0, 0)); console.log(d.toLocaleString()); console.log(d.getTimezoneOffset());
displayed:
‎01‎/‎07‎/‎1970‎ ‎01:‎00‎:‎00 <= ok, no DST in june 1970, +1:00
-120 <= same problem, should be -60 here too
And also, same thing in Firefox, worse in IE/Edge (01‎/‎07‎/‎1970‎ ‎02:‎00‎:‎00).
I did this for equinox and solistice. You can use the function for any Julian date.
It returns the Julian date in the calender date format: day/month.
Include year and you can format it anyway you want.
It's all there, year, month, day.
Since Equinox and Solistice are time stamps rather than dates, my dates in the code comes back as decimals, hence "day = k.toFixed(0);". For any other Julian date it should be day = k;
// For the HTML-page
<script src="../js/meuusjs.1.0.3.min.js"></script>
<script src="../js/Astro.Solistice.js"></script>
// Javascript, Julian Date to Calender Date
function jdat (jdag) {
var jd, year, month, day, l, n, i, j, k;
jd = jdag;
l = jd + 68569;
n = Math.floor(Math.floor(4 * l) / 146097);
l = l - Math.floor((146097 * n + 3) / 4);
i = Math.floor(4000 * (l + 1) / 1461001);
l = l - Math.floor(1461 * i / 4) + 31;
j = Math.floor(80 * l / 2447);
k = l - Math.floor(2447 * j / 80);
l = Math.floor(j / 11);
j = j + 2 - 12 * l;
i = 100 * (n - 49) + i + l;
year = i;
month = j;
day = k.toFixed(0); // Integer
dat = day.toString() + "/" + month.toString(); // Format anyway you want.
return dat;
}
// Below is only for Equinox and Solistice. Just skip if not relevant.
// Vernal Equinox
var jv = A.Solistice.march(year); // (year) predefined, today.getFullYear()
var vdag = jdat(jv);
// Summer Solistice
var js = A.Solistice.june(year);
var ssol = jdat(js);
//Autumnal Equinox
var jh = A.Solistice.september(year);
var hdag = jdat(jh);
// Winter Solistice
var jw = A.Solistice.december(year);
var vsol = jdat(jw);

Categories