Convert Ble Current Time to Date

Convert BLE current time to date

To convert from data/bytes to numeric types you can check this post

extension Numeric {
init<D: DataProtocol>(_ data: D) {
var value: Self = .zero
let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
assert(size == MemoryLayout.size(ofValue: value))
self = value
}
}

extension DataProtocol {
func value<N: Numeric>() -> N { .init(self) }
var uint16: UInt16 { value() }
}

Now you can easily convert from bytes to any numeric type:

let timeData: [UInt8] = [224, 7, 1, 3, 4, 36, 5, 0, 0, 1]
let timeDate = DateComponents(calendar: .current,
timeZone: .current,
year: Int(timeData[0..<2].uint16),
month: Int(timeData[2]),
day: Int(timeData[3]),
hour: Int(timeData[4]),
minute: Int(timeData[5]),
second: Int(timeData[6])).date!
timeDate // "Jan 3, 2016 at 4:36 AM"

Convert Date to Hex String using Swift (BLE)

That is what I was looking for:

let dateInt = Int(Date().timeIntervalSince1970)
let dateHex = String(dateInt, radix: 16, uppercase: true)
print(dateHex)

Now dateHex could be devided on bites and sent to BLE device

How to convert Swift Date into Byte Array?

You can create a method to convert FixedWidthInteger to bytes (big or little endian) for the year component, convert the other date componentes to bytes and append them to the result:

enum Endianness {
case big, little
}

extension FixedWidthInteger {
func data<D: DataProtocol & RangeReplaceableCollection>(
using endianness: Endianness = .big
) -> D {
withUnsafeBytes(of: endianness == .big ? bigEndian : littleEndian, D.init)
}
}


extension Calendar {
static let iso8601 = Self(identifier: .iso8601)
}


extension Date {
func component(_ component: Calendar.Component, using calendar: Calendar = .iso8601) -> Int {
calendar.component(component, from: self)
}
func data<D: DataProtocol & RangeReplaceableCollection>() -> D {
var dataProtocol: D = .init()
dataProtocol += UInt16(component(.year)).data() as D
dataProtocol.append(UInt8(component(.month)))
dataProtocol.append(UInt8(component(.day)))
dataProtocol.append(UInt8(component(.hour)))
dataProtocol.append(UInt8(component(.minute)))
dataProtocol.append(UInt8(component(.second)))
return dataProtocol
}
}

Usage:

let data: Data = Date().data()
print(Array(data))

This will print

[7, 230, 6, 17, 2, 10, 46]

Convert Hex code to Date (BLE) - Algorithm

The data is the big-endian representation of the date offset to the
“reference date” (00:00:00 UTC on 1 January 2001):

let data = Data(bytes: [0xBA, 0x36, 0x8E, 0x7F])
let offset = UInt32(bigEndian: data.withUnsafeBytes { $0.pointee })
let date = Date(timeIntervalSinceReferenceDate: TimeInterval(offset))
print(date) // 2099-12-31 23:59:59 +0000

If the input is really given as a hex string, not as Data:

let hex = "BA368E7F"
if let offset = UInt32(hex, radix: 16) {
let date = Date(timeIntervalSinceReferenceDate: TimeInterval(offset))
print(date) // 2099-12-31 23:59:59 +0000
}

Convert DATA to Date

The necessary information can be found in Data to different types ? in the Apple Developer Forum.

First note that it is unsafe to rely on undocumented extended attributes. A better way to get the same result is to retrieve the NSMetadataItemLastUsedDateKey from an NSMetadataItem:

if let date = NSMetadataItem(url: url)?.value(forAttribute: NSMetadataItemLastUsedDateKey) as? Date {
print(date)
}

But to answer your actual question: That extended attribute holds a
UNIX struct timespec (compare <time.h>) value. That is the type used for st_atimespec and other members of struct stat (which in turn is the type used with fstat() and similar system calls).

You have to copy the data into a timespec value, compute the seconds from the tv_sec and tv_nsec members, and then create a Date from the seconds since the Unix epoch.

func dataToDate(data: Data) -> Date {
var ts = timespec()
precondition(data.count >= MemoryLayout.size(ofValue: ts))
_ = withUnsafeMutableBytes(of: &ts, { lastuseddata.copyBytes(to: $0)} )
let seconds = TimeInterval(ts.tv_sec) + TimeInterval(ts.tv_nsec)/TimeInterval(NSEC_PER_SEC)
return Date(timeIntervalSince1970: seconds)
}

Example (your data):

let lastuseddata = Data([0xb9, 0xb6, 0xc3, 0x5e, 0x00, 0x00, 0x00, 0x00,
0xab, 0xd7, 0x32, 0x25, 0x00, 0x00, 0x00, 0x00])

print(dataToDate(data: lastuseddata))
// 2020-05-19 10:36:41 +0000

reverse engineer hex values to time date format

thx for your answer.

I discovered how the date and time is decoded.
Grp 3 and Grp 2 is in little endian the unix time but starting strangely from year 2010 and not from 1970.

So I have to add 40 years to get the correct year.

For example:

00:fe:a6:11:f5:0d:c7:19:00:ff:01:09:00:00:00:00  --> 03.06.2017 - 07:44:06

unix time decoded:

0d:f5:11:a6 --> 234164646 -> unix time stamp 1977-06-03T05:44:06+00:00 in ISO 8601

adding 40 years to this unix time stamp I get the correct date and time.

Android BLE: Convert ScanResult timestampNanos to System nanoTime

Use the following code to convert the getTimestampNanos() to system millis by using SystemClock.elapsedRealtime():

long rxTimestampMillis = System.currentTimeMillis() - 
SystemClock.elapsedRealtime() +
scanResult.getTimestampNanos() / 1000000;

This can be converted easily to a Date object:

Date rxDate = new Date(rxTimestampMillis);

Then you then get the time as a string:

String sDate = new SimpleDateFormat("HH:mm:ss.SSS").format(rxDate);


Related Topics



Leave a reply



Submit