PureBasic to Xojo

I have a PureBasic code snippet and I’m wondering if somebody knows the syntax and can translate it to Xojo:

[code]Procedure Event_DateFormat(Date.i)

Protected Time.i = Val("$"+FormatDate("%hh%ii%ss", Date))
ProcedureReturn (Int(date/(606024))+40587)<<24 | Time


Thanks in advance

Are you trying to convert time to 24 hour format? Whats your intent on the above code?

That converts a date into a 24bit format that is used by
Event Information Table (EIT)


I assume you are referring to the:
event_information_table_section () {start_time} ?


Yes, that’s right.

OK, looking at the spec, found at http://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.03.01_60/en_300468v010301p.pdf

To summarize, there are two date/time formats in the spec. The 24-bit format is used for durations, with 8-bit fields for hour, minute, and second; the tricky part is that these fields are binary-coded-decimal. Full-on dates are 40 bits, with the first 16 being the modified Julian day and the last 24 the time (UTC) as above.

Given the nature of the format, these will normally be, I imagine, coming out of or going into a BinaryStream. Thus, four methods appear logical: reading or writing a duration, and reading or writing a date+time.

Methods to follow in next post, but here’s a pair of utility methods:

Function BCDToDecimal(i as integer) as integer If i<16 then Return i Else Return (i\\16) + 10*BCDToDecimal(i mod 16) End if

Function DecimalToBCD(i as integer) as integer If i<10 then Return i Else Return (i\\10) + 16*DecimalToBCD(i mod 10) End if

Function ReadEITDuration(Extends bs as BinaryStream) as Date Dim dt as new date Dt.gmtoffset = 0 dt.totalseconds = 0 dt.Hour = BCDToDecimal(bs.readUInt8) dt.Minute = BCDToDecimal(bs.readUInt8) dt.Second = BCDToDecimal(bs.readUInt8) Return dt

Function ReadEITDuration(Extends bs as BinaryStream) as Date Dim dt as new date Dt.gmtoffset = 0 dt.totalseconds = (60*60*24)*(bs.ReadUInt16-16480) dt.Hour = BCDToDecimal(bs.readUInt8) dt.Minute = BCDToDecimal(bs.readUInt8) dt.Second = BCDToDecimal(bs.readUInt8) Return dt

Note that the LittleEndian property of the BinaryStream should be false, because the EN 300 468 format is inherently big-endian. Also, note that the date returned is a UTC date. (The constant 16480 is the modified Julian date for 1 January 1904, the zero point of Xojo dates.)

Correction: the two functions should not have the same name. The second should be ReadEITDateTime.

Sub WriteEITDuration(Extends bs as BinaryStream, dt as date) bs.WriteUInt8(DecimalToBCD(dt.Hour)) bs.WriteUInt8(DecimalToBCD(dt.Minute)) bs.WriteUInt8(DecimalToBCD(dt.Second))

Sub WriteEITDateTime(Extends bs as BinaryStream, dt as date) Dim dt0 as new date dt0.gmtOffset = 0 dt0.totalseconds = dt.totalseconds - (60*60*dt.gmtOffset) bs.WriteUInt16((dt0.totalseconds\\(60*60*24))+16480) bs.WriteUInt8(DecimalToBCD(dt.Hour)) bs.WriteUInt8(DecimalToBCD(dt.Minute)) bs.WriteUInt8(DecimalToBCD(dt.Second))

Wow! You did a lot of work. Thanks!
Unfortunately I am not sure if this is what I need.

What I am trying to do is read and write a EIT file.
This is a simple text file of a description of a recorded tv show.

Everything works so far except the StartTime (recording date/time) that is encoded at the header of the file.

The recording date is: 21.04.2014 | 08:55 (date | time)
The recording duration is: 95 minutes

This is the header of the file:

Byte 1 = Chr(116)
Byte 2 = Chr(238)
Byte 3 = Chr(221)
Byte 4 = Chr(192)
Byte 5 = Chr(6)
Byte 6 = Chr(85)
Byte 7 = Chr(0)
Byte 8 = Chr(1)
Byte 9 = Chr(53)

I know the duration is encoded within byte 8 and byte 9
That is easy:
Byte 8 = Chr(1) >> hex 1 = dec 1 --> 1 hour
Byte 9 = chr(53) >> hex 53 = dec 35 --> 35 minutes

The recording date/time is encoded with byte 3, byte 4, byte 5, byte 6 and byte 7
Now I am looking for a way to transform the ASCII-Code of these characters to the date/time

Is this possible with the code you posted?

btw. inside byte 1 and byte 2 is the event ID and this is not important for me.

I found this description for the start date/time.

[quote]start_time: This 40-bit field contains the start time of the event in Universal Time, Co-ordinated (UTC) and Modified Julian Date (MJD) (see annex C). This field is coded as 16 bits giving the 16 LSBs of MJD followed by 24 bits coded as 6 digits in 4-bit Binary Coded Decimal (BCD). If the start time is undefined (e.g. for an event in a NVOD reference service) all bits of the field are set to “1”.
EXAMPLE 1: 93/10/13 12:45:00 is coded as “0xC079124500”.[/quote]

But I can’t see how to calculate the ASCII characters for the header. (read & write)

I just checked Andrew’s (J Andrew’s?) code, and it’s dead on. From the data you posted, I can extract the date 2014-04-21 06:55:00 (GMT) using his code. I haven’t checked the encoding, but that seems right too.

I feel so stupid.
I am not very experienced with BinaryStream and I can not see how to use Andrew’s code.

Dim s As String s = Chr(221) + Chr(192) + Chr(6) + Chr(85) + Chr(0)

What to do now to get the date?
And how I get the string if I provide the date?

Sorry for the dumb question!
That looks so complicated to me compared to the PureBasic code I posted in my first post…

How are you reading the header in the first place? How are you getting those byte values?

I read the file with TextInputStream and then I use Mid

Here is the file I used in my example:

You shouldn’t be using a TextInputStream because the file isn’t really text, it’s a series of bytes. Instead, you would use a BinaryStream to read it byte by byte or value by value.

In this case, you would set up a Structure to represent the header, read the data into the structure, and extract each element. Check the Language Reference for more information.

To modify Andrew’s code to meet your needs, you could supply the five bytes that make up the date/time to this method to extract the date, or supply a date to extract the data to write:

Function ReadEITDate(value As MemoryBlock) as Date
  value.LittleEndian = False
  Dim dt as new date
  Dt.gmtoffset = 0
  dt.totalseconds = (60*60*24)*(value.UInt16Value( 0 )-16480)
  dt.Hour = BCDToDecimal( value.Byte( 2 ))
  dt.Minute = BCDToDecimal(value.Byte( 3 ))
  dt.Second = BCDToDecimal(value.Byte(4))
  Return dt
End Function
Function WriteEITDateTime(dt as date) As MemoryBlock
  Dim dt0 as new date
  dt0.gmtOffset = 0
  dt0.totalseconds = dt.totalseconds - (60*60*dt.gmtOffset)

  dim m as new MemoryBlock( 5 )
  m.UInt16Value( 0 ) = (dt0.totalseconds\\(60*60*24))+16480
  m.Byte( 2 ) = DecimalToBCD(dt0.Hour)
  m.Byte( 3 ) = DecimalToBCD(dt0.Minute)
  m.Byte( 4 ) = DecimalToBCD(dt0.Second)
  return m
End Function

Strings and MemoryBlocks can be converted easy just through assignment, so you could call this function as:

s = Chr(221) + Chr(192) + Chr(6) + Chr(85) + Chr(0)
dim d as Date = ReadEITDate(s) 

Thank you very much. I am really grateful for that.

I combined the code from Andrew and Kem in a little Xojo app.

But the result is not as expected.
The date returns as: 19.11.1859 | 18:08

Two issues.

First, the way you are constructing the data string. You are using Chr which will return the Unicode character. That will be two or more bytes for values greater than 127. Use ChrB instead to get a single byte.

Second, the formula has to use doubles to properly do the calculation. Right now, everything is either an integer or (worse) and UInt16, so change the formula to this:

  dt.totalseconds = (60.0*60.0*24.0)*(value.UInt16Value( 0 )-16480.0)

This will force everything to Double, and that will be able to properly compute and hold the result.

Make the same change in formula for writing.

Reading works now perfectly. :slight_smile:
The time is 2hr earlier as expected but that is our time offset here in Germany and I can handle it.

But there is still something wrong with the writing method.
The first 2 bytes of the returning MemoryBlock are wrong
They should be:

but they are:
49 DF

Now I know what is wrong. :slight_smile:

There was a backslash in the code:

 m.UInt16Value( 0 ) = dt0.totalseconds\\(60*60*24)+16480

Now everything works

 m.UInt16Value( 0 ) = dt0.totalseconds/(60*60*24)+16480

Thanks again to all who helped me!!!
I’ve learned a lot today!