2

I have two dates in JavaScript, start and finish, parsed by Moment.js. What would be the most efficient way to swap them if start is posterior to finish without having to create a third date? Typically, the dates would be parameters of a function like this one:

function getDates(start, finish) {
  var start_date = moment(new Date(start));
  var finish_date = moment(new Date(finish));
  if (start_date.diff(finish_date) > 0) {
    // Swap code goes here...
  }
}

The reason why one might want to swap dates is because some functions are defined in such a way that the same result is returned even if the dates are swapped, yet the function needs to know which date is the earlier one. For example, YEARFRAC in Microsoft Excel works that way. You can see my implementation of that function here for an example of a sub-optimal date swapping.

Thanks in advance for your help!

Ismael Ghalimi
  • 3,515
  • 2
  • 22
  • 25
  • 2
    You know you can literally get the MS time of a date, then set it in the other date, similar to (new Date().getTime()) then do set date on the other – adrian Jan 21 '13 at 02:04
  • 2
    Why can't you have a third variable? var x = start_date; start_date = finish_date; finish_date = x. This way you are not creating a _third date_, although I suspect, _third variable_ is what you meant. And if so why is that a constraint? – Kind Contributor Jan 21 '13 at 02:06
  • i don't know if you should go around swapping dates, unless one is unusually hotter than the other... – thang Jan 21 '13 at 02:10
  • Just trying to be as efficient as possible. There are ways to do that for numbers with binary operators, and I was curious to learn if anyone had devised a way to do something similar with dates. – Ismael Ghalimi Jan 21 '13 at 02:10
  • @thang, I added an explanation of why such swapping needs to occur. – Ismael Ghalimi Jan 21 '13 at 02:15

3 Answers3

2

What would be the most efficient way to swap them if start is posterior to finish

With a third variable. For fun, you could use a destructuring assignment to prevent that work syntactically around that, but this will hardly make a performance difference.

without having to create a third date?

That's the point of using a variable. With the binary operator way you mentioned you would need to cast the Date object to an integer, apply the operation, and then create two new Date objects from the integers.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

If your constraint against having an additional Date should be interpreted as not having another variable at all, then I have a solution based on this person's brilliant idea for inline variable swapping:

function getDates(start, finish) {
    var start_date = new Date(2013, 0, 5);
    var finish_date = new Date(2013, 0, 4);
    start_date = start_date.getTime();
    finish_date = finish_date.getTime();
    start_date = -(finish_date = (start_date += finish_date) - finish_date) + start_date;
    start_date = new Date(start_date);
    finish_date = new Date(finish_date);
    alert(start_date);
    alert(finish_date);
}
Joe DeRose
  • 3,438
  • 3
  • 24
  • 34
  • 1
    You do know that this sorts the dates by their string serialisation? – Bergi Jan 21 '13 at 02:32
  • I get it, but this tells me that I might be trying to find a solution to a problem that does not really exist. A third variable might be all it takes, and anything else will be more complex and less efficient. – Ismael Ghalimi Jan 21 '13 at 02:49
  • I've modified my response to remove the array solution. My second suggestion (still visible above) was more in keeping with your question anyway, and the comment by @Bergi led me to realize that there were aspects of the string serialization that I didn't take into account with the array sorting approach. The array solution could have been made to work with a minimal amount of additional code -- but since you've already acknowledged that a third Date is the best way to go, I've just removed the buggy lines rather than re-write them. – Joe DeRose Jan 21 '13 at 10:47
0

I'm not sure to have understood what you need but, if you pass the timestamp to start and finish, with something like this:

start_date = start > finish ? finish : start;
finish_date = start > finish ? start : finish;

you swap the values without the third temporary variable. Then you can create the moment objects and work with them. For example:

function dateDiff( start, finish, measure ){
  var start_date = start > finish ? finish : start, 
      finish_date = start > finish ? start : finish;
  return moment(finish_date).diff(moment(start_date), measure);
}

dateDiff( new Date(2013,1,21), new Date(2013,1,28), 'days' ) // 7
dateDiff( new Date(2013,1,28), new Date(2013,1,21), 'days' ) // 7

If you need only to know the positive difference you can even do:

date_diff = (start < finish ? finish : start) - (start < finish ? start : finish);

EDIT:

However, it's possible to test that even with ternary operators the performance is lower than the classic if..else statement.

Hope this might be of some help.

Ragnarokkr
  • 2,328
  • 2
  • 21
  • 31