Asked — Edited

Date And Time Question

Can anyone point me in the direction to find a way to tell how much time there is between two dates.

For example Date1 = 10/29/2016 10:30:54 PM and Date2 = 10/28/2016 7:00:01 AM

How many days, hours, minutes, and seconds before date 1.


ARC Pro

Upgrade to ARC Pro

Stay on the cutting edge of robotics with ARC Pro, guaranteeing that your robot is always ahead of the game.

#1  

You'd need to break down the days and time separately then subtract. Have you got a script example you are working on?

PRO
USA
#2  

@Dbeard,

EZ-Script has a few limitations and some parser bugs.
If you are doing complex or repetitive calculations, I would invest my time in a Plugin.


$fromDate = "10/27/2016 1:00:00 PM"
#$fromDate = now()
$toDate   = "10/28/2016 1:00:00 AM"

DefineArray($tmp_ar, 22, 0)
# Working Array 
# pos description
#  0 - fromDate - year
#  1 - fromDate - month
#  2 - fromDate - day
#  3 - fromDate - hour
#  4 - fromDate - minutes
#  5 - fromDate - seconds
#  6 - fromDate - leap year : 1=yes 0=no
#  7 - fromDate - month's days
#  8 - toDate   - year
#  9 - toDate   - month
# 10 - toDate   - day
# 11 - toDate   - hour
# 12 - toDate   - minutes
# 13 - toDate   - seconds
# 14 - toDate   - leap year : 1=yes 0=no
# 15 - toDate   - month's days
# 16 - total    - year(s)
# 17 - total    - month(s)
# 18 - total    - day(s)
# 19 - total    - hour(s)
# 20 - total    - minute(s)
# 21 - total    - second(s)


#parse fromDate
$ParseDate_IN_DateTime=$fromDate
$ParseDate_IN_StartIndex=0
Goto(ParseDate)

#parse toDate
$ParseDate_IN_DateTime=$toDate
$ParseDate_IN_StartIndex=8
Goto(ParseDate)
  
Goto(CalcDiff)

Print("fromDate:" + $fromDate)
Print("  toDate:" + $toDate)
Goto(PrintDiff)  
  
Halt()  
  
  
: PrintDiff  
  #ARC bug don't use ( in a string
  if ($tmp_ar[16]>0)
    Print($tmp_ar[16] + " year[s]" )
  endif 
  if ($tmp_ar[17]>0)
    Print($tmp_ar[17] + " month[s]" )
  endif 
  if ($tmp_ar[18]>0)
    Print($tmp_ar[18] + " day[s]" )
  endif 
  if ($tmp_ar[19]>0)
    Print($tmp_ar[19] + " hour[s]" )
  endif 
  if ($tmp_ar[20]>0)
    Print($tmp_ar[20] + " minute[s]" )
  endif 
  if ($tmp_ar[21]>0)
    Print($tmp_ar[21] + " second[s]" )
  endif 
  
  Return()
  
:CalcDiff
  #expects:
  #  tmp_ar : array with at least 22 elements (0..7=fromDate, 8..15=toDate, 16..21=#totals)
  
  #Note:  EZ-Script parser bug (need spaces when combining multiple inline operations)
  
  #tmp1 is used to flag an overflow
  
  #calculate #seconds
  if ($tmp_ar[5] > $tmp_ar[13])
    $tmp_ar[21]=$tmp_ar[13] + 60 - $tmp_ar[5]
    $tmp1=1 
  else
    $tmp_ar[21]=$tmp_ar[13] - $tmp_ar[5]
    $tmp1=0
  endif
  
  #calculate #minutes
  if ($tmp_ar[4] + $tmp1>$tmp_ar[12])
    $tmp_ar[20]=$tmp_ar[12] + 60 - $tmp_ar[4] - $tmp1 
    $tmp1=1
  else 
    $tmp_ar[20]=$tmp_ar[12] - $tmp_ar[4] - $tmp1 
    $tmp1=0
  endif

  #calculate #hours
  if ($tmp_ar[3] + $tmp1>$tmp_ar[11])
    $tmp_ar[19] = $tmp_ar[11] + 24 - $tmp_ar[3] - $tmp1
    $tmp1 = 1
  else
    $tmp_ar[19] = $tmp_ar[11] - $tmp_ar[3] - $tmp1
    $tmp1 = 0
  endif

  #calculate #days
  if ($tmp_ar[2] + $tmp1> $tmp_ar[10])
    $tmp_ar[18]=$tmp_ar[10] + $tmp_ar[7] - $tmp_ar[2] - $tmp1
    $tmp1=1 
  else
    $tmp_ar[18]=$tmp_ar[10] - $tmp_ar[2] - $tmp1
    $tmp1=0
  endif

  #calculate #months
  if ($tmp_ar[1] + $tmp1>$tmp_ar[9])
    $tmp_ar[17]=$tmp_ar[9] + 12 - $tmp_ar[1] - $tmp1 
    $tmp1=1
  else 
    $tmp_ar[17]=$tmp_ar[9] - $tmp_ar[1] - $tmp1 
    $tmp1=0
  endif

  #calculate #years
  $tmp_ar[16] = $tmp_ar[8] - $tmp_ar[0] - $tmp1
  
  Return()


  
  
:ParseDate
  #expects: 
  #   $ParseDate_IN_DateTime  : variable with the datetime EN-US format
  #   ParseDate_IN_StartIndex : Index to store the datetime in the array (0=first date, 8=second date, 16=next date) 
   
  $tmp1=split($ParseDate_IN_DateTime, " ", 0)
  $tmp_ar[$ParseDate_IN_StartIndex]=cint(split($tmp1, "/", 2))
  $tmp_ar[$ParseDate_IN_StartIndex+1]=cint(split($tmp1, "/", 0))
  $tmp_ar[$ParseDate_IN_StartIndex+2]=cint(split($tmp1, "/", 1))

  $tmp1=split($ParseDate_IN_DateTime, " ", 1)
  $tmp_ar[$ParseDate_IN_StartIndex+3]=cint(split($tmp1, ":", 0))
  $tmp_ar[$ParseDate_IN_StartIndex+4]=cint(split($tmp1, ":", 1))
  $tmp_ar[$ParseDate_IN_StartIndex+5]=cint(split($tmp1, ":", 2))

  #convert am/pm to 24 hours (0..23)
  $tmp1=split($ParseDate_IN_DateTime, " ", 2)
  if ($tmp1="AM" AND $tmp_ar[$ParseDate_IN_StartIndex+3]=12)
    $tmp_ar[$ParseDate_IN_StartIndex+3]=0
  elseif ($tmp1="PM" AND $tmp_ar[$ParseDate_IN_StartIndex+3]<12)
    $tmp_ar[$ParseDate_IN_StartIndex+3]=$tmp_ar[$ParseDate_IN_StartIndex+3]+12  
  endif
  
  #leap year calculation
  $tmp1=$tmp_ar[$ParseDate_IN_StartIndex] % 4
  $tmp2=$tmp_ar[$ParseDate_IN_StartIndex] % 100
  $tmp3=$tmp_ar[$ParseDate_IN_StartIndex] % 400
  
  if ($tmp1=0 AND $tmp2!=0)
    $tmp_ar[$ParseDate_IN_StartIndex+6]=1
  elseif ($tmp3=0)
    $tmp_ar[$ParseDate_IN_StartIndex+6]=1
  else
    $tmp_ar[$ParseDate_IN_StartIndex+6]=0
  endif

  #number of days in the month calculation
  $tmp1=$tmp_ar[$ParseDate_IN_StartIndex+1]
  if ($tmp1=2)
    $tmp_ar[$ParseDate_IN_StartIndex+7]=28+$tmp_ar[$ParseDate_IN_StartIndex+6]
  elseif ($tmp1=4 OR $tmp1=6 OR $tmp1=9 OR $tmp1=11)
    $tmp_ar[$ParseDate_IN_StartIndex+7]=30
  else
    $tmp_ar[$ParseDate_IN_StartIndex+7]=31
  endif
  Return()

c# version:


var fromDate = DateTime.ParseExact("10/28/2016 7:00:01 AM", "M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture);
var toDate = DateTime.ParseExact("10/29/2016 10:30:54 PM", "M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture);
Console.WriteLine("{0:%d} days, {0:%h} hours, {0:%m} minutes, {0:%s} seconds", toDate - fromDate);

output:

User-inserted image

PRO
USA
#3  

Thanks, ptp. I appreciate the code, not sure my skills are up to coding a plugin. I have trouble manipulating a date. I will start reviewing the plugin documentation and tutorial to see if I can figure it out.

PRO
USA
#4  

@dbeard,

fixed a bug and added comments to explain my logic.

PRO
Synthiam
#5  

[feature] DateTime Functions MinDate() MaxDate() MonthName() AddDays() AddMonths() AddYears() AddHours() AddMinute() AddSeconds() FmtNum()

  • Get number format from <https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx> FmtDate()
  • Get date format from <https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx>

Casting Functions These functions are to cast objects from one datatype to another To Double: CDBL() To Integer: CInt() To Long: CLong() To Unsigned Integer: CUint() To Unsigned Long: CULong() To DateTime: CDateTime() [/feature]


$startDate = &quot;10/29/2016 1:00:00 PM&quot;
$endDate = &quot;10/28/2016 2:02:02 PM&quot;

$diff = CDateTime($startDate) - CDateTime($endDate)

print($diff)

PRO
USA
#6  

@DJ,

That's a major refactoring! I tried that before but does not work as the OP wants. does not handle days, months, years.


$fromDate = &quot;11/17/1974 10:00:00 PM&quot;
$toDate   = &quot;10/27/2016 4:29:00 PM&quot;
$diff = CDateTime($toDate) - CDateTime($fromDate)
print($diff)

Check the output: User-inserted image

PRO
Synthiam
#7  

Your code is very fun and impressive! You could save a bit of code by parsing the output of this...


$startDate = &quot;10/29/2016 1:00:00 PM&quot;
$endDate = &quot;5/28/2014 2:02:02 PM&quot;

$diff = CDateTime($startDate) - CDateTime($endDate)

The $diff in this case is 884.22:57:58. That's

  • 884 days
  • 22 hours
  • 57 minutes
  • 58 seconds

I just added a fmttimespan() to EZ-Script for the next release. It will allow formatting of a timespan (which is what a datetime subtraction/addition creates)

PRO
USA
#8  

@DJ,

yes it was more an exercise i can't do that in my day job :)

I like to test concepts: Goto / Return (like a function call) Working with an array to minimize variable usage Reusing a (function call)

everything went well.

yes i could parse the big number (days), but i would need to calculate the leap years, to extract years, then how many leap years in between, so i decided to do it from scratch.

PRO
Synthiam
#9  

It's awesome :D

I have been fiddling with the idea of making user defined functions in ez-script. It would be a control where you can define the function and parameters.

My first thought was to make the function be ez-script. But lately i've been leaning toward the idea of having the function be c# to give additional functionality. That means you could create the c# code for the internal function and be a) extra fast b) have control over the ARC architecture just like a plugin

#10  

@DJ... Great idea.... User defined functions would be awesome....

PRO
USA
#11  

@DJ,

I'm glad you raised that topic.

Plugin: the concept is neat, but as you know does not work on Mobile and Windows Universal Apps

user functions: I would do it first in EZ-Script, as you know C# CodeDom/Generation is not allowed on IOS Apps.

that way you can use user functions everywhere.

PRO
Synthiam
#12  

I was thinking of the user function being similar to a plugin's version management and shareable in an online library.

if the function is a mere EZ-Script and defined on a per project basis, there would be no version control and outdated/bugger functions would be difficult to manage across projects.

I'll think a bit on what an EZ-Script user function with online version management simlar to a plugin would look like. hmmm...

#13  

While we're on the topic... (and assuming I got the gist of this function idea).... A function or library for serial would be great... I am just ok at serial stuff, but streamlining serial receive would be welcome...

PRO
USA
#14  

@Richard R,

Can you elaborate.

#15  

@PTP.... I would like to just read serial into a variable in a function call... avoiding GetByteAt, UARTAvailable, UARTRead, etc....

And maybe even a simple parser... $string=(left($string),10,5) Something like this would set $string as the 10th character in and read for 5 characters after.... This way you can pick the data you want out of the incoming serial data

PRO
Synthiam
#16  

How would you know if any data had been transmitted, how to tell if a packet had been received without UartAvailable()?

Why are you ever GetByteAt() anyway? That's not a serial specific function - it's a function to get a byte(character) within a string

#17  

@DJ I was using GetByteAt when I was using my Roomba ...example code snippet...


$RX_DATA=0
  uartWrite(0,0,142,22) # Volatge check
  sleep(10)
  uartWrite(0,0,142,21) # charge state
  sleep(10)
  uartWrite(0,0,142,34) # charge state
  sleep(50)
  $rx = UartAvailable(0, 0)


  if ($rx=4)
    $RX_DATA = UARTRead(0, 0, $rx)
    $MSB=GetByteAt($RX_DATA,0)
    $LSB=GetByteAt($RX_DATA,1)
    $Charge=GetByteAt($RX_DATA,2)
    $Charge_source=GetByteAt($RX_DATA,3)
    $voltage=Round(($LSB+(256*$MSB))/1000,2)

#18  

@PTP, @DJ... So my idea was a function call something like this... Not knowing C# limits my understanding of what can be done here so apologies...


$data=GetSerialData()

What ever is in the buffer (if anything) would be read into $data... The complexity is removed... And It would be up to the user to pick out and/or convert the data he wants using maybe simple parser....

PRO
Synthiam
#19  

So what happens when you call "GetSerialData()" and you only get 1 byte, but your example code looks like it isexpecting 4 bytes.

This is the reason you have..


$rx = UartAvailable(0, 0)


  if ($rx=4)
....

You can't trust that you ha

PRO
Synthiam
#20  

ve received all the data with a single command.

(see what i did there?)

#21  

@DJ... Ha, Ha... Touché..... Still function() commands to return data is a good idea... :)

PRO
Synthiam
#22  

No, it's not a good idea, as the example was presented :)

Additionally, using UARTRead() with binary/byte data is not recommended. UARTRead(), as the documentation dictates, is for ASCII String data.

Use UARTReadBinary(), which puts the data into an array.

To read all contents in one line, use this...


UARTReadBinary(0, UARTAvailable(0, 0), $array)

or for ASCII Read all, it's


$data = UARTReadAvailable( 0, 0 )

Here's the info from the EZ-Script manual in ARC:

[feature] UARTRead( boardIndex, port, numBytes ) Receive ASCII bytes from the Peripheral UART Receive Buffer of the EZ-B v4. The UART receive buffers on the EZ-B v4 are 5,000 bytes. To know how many bytes are available, use the UARTAvailable() function. The Board Index is the EZ-B index starting at 0. The port can be 0, 1 or 2. Look near at the UART Port section lower in this document for the EZ-B Pin’s associated with each UART Port. Example: UARTRead(0, 0, 10) Example: UARTRead(0, 0, UARTAvailable(0, 1))

UARTReadBinary( boardIndex, port, numBytes, variable ) Receive binary bytes from the Peripheral UART Receive Buffer of the EZ-B v4 into the variable as an array. The UART receive buffers on the EZ-B v4 are 5,000 bytes. To know how many bytes are available, use the UARTAvailable() function. The Board Index is the EZ-B index starting at 0. The port can be 0, 1 or 2. Look near at the UART Port section lower in this document for the EZ-B Pin’s associated with each UART Port. Example: UARTReadBinary(0, 0, 10, $variable) Example: UARTReadBinary(0, 0, UARTAvailable(0, 1), $variable)

UARTReadAvailable( boardIndex, port ) Receive all available ASCII bytes from the Peripheral UART Receive Buffer of the EZ-B v4. The UART receive buffers on the EZ-B v4 are 5,000 bytes. The Board Index is the EZ-B index starting at 0. The port can be 0, 1 or 2. Look near at the UART Port section lower in this document for the EZ-B Pin’s associated with each UART Port. Example: UARTReadAvailable(0, 0) Example: UARTReadAvailable(0, 0) [/feature]

#23  

@DJ.... Got you. I do understand how it works, I just have to experiment further with UART... Learning to better parse the incoming information for the relevant data that I need is the next step....:) Thanks

PRO
Synthiam
#24  

Did you also notice that the command you were asking for exists? I pasted it in the above message from the script manual. It's uartreadavailable(). It's just that I wouldn't recommend using it for your application.

Actually, I wouldn't use it for any application other than debugging. Because you do need to know how much data is in the buffer. And you should only read as much data as your expected packet size is and leave the other packets in the buffer to process on the next loop.

#25  

@DJ... Yes, last night I went over and re-read all the UART documentation... I didn't pay much attention to what uartreadavailable() really does as I only used what I needed when I was messing with the UART and roomba.... I am going to go back and do some more experimenting... Thanks as always