erva 2 Posted April 20, 2020 I'am reading calls from Android call log. Date format is something that Delhi don't recognise. Date is returned like this: "1587377791601". Any idea what this number means and how to get date and time from it? Here's code what works, i have commented out lines what i don't want use. In commented lines is (StringToJString(...)) but it must be ( TJCallLog_Calls.JavaClass....) : var cursor: JCursor; uri: Jnet_Uri; CACHED_FORMATTED_NUMBER, CACHED_LOOKUP_URI, CACHED_MATCHED_NUMBER, CACHED_NAME, CACHED_NORMALIZED_NUMBER, CACHED_NUMBER_LABEL, CACHED_NUMBER_TYPE, CACHED_PHOTO_ID, CONTENT_ITEM_TYPE, CONTENT_TYPE, COUNTRY_ISO, DATA_USAGE, DATE, DEFAULT_SORT_ORDER, DURATION, EXTRA_CALL_TYPE_FILTER, FEATURES, IS_READ, LIMIT_PARAM_KEY, NEW, NUMBER, NUMBER_PRESENTATION, OFFSET_PARAM_KEY, PHONE_ACCOUNT_COMPONENT_NAME, PHONE_ACCOUNT_ID, TRANSCRIPTION, TYPEX, VOICEMAIL_URI : integer; msgunixtimestampms:int64; CACHED_FORMATTED_NUMBERx, CACHED_LOOKUP_URIx, CACHED_MATCHED_NUMBERx, CACHED_NAMEx, CACHED_NORMALIZED_NUMBERx, CACHED_NUMBER_LABELx, CACHED_NUMBER_TYPEx, CACHED_PHOTO_IDx, CONTENT_ITEM_TYPEx, CONTENT_TYPEx, COUNTRY_ISOx, DATA_USAGEx, DATEx, DEFAULT_SORT_ORDERx, DURATIONx, EXTRA_CALL_TYPE_FILTERx, FEATURESx, IS_READx, LIMIT_PARAM_KEYx, NEWx, NUMBERx, NUMBER_PRESENTATIONx, OFFSET_PARAM_KEYx, PHONE_ACCOUNT_COMPONENT_NAMEx, PHONE_ACCOUNT_IDx, TRANSCRIPTIONx, TYPEXx, VOICEMAIL_URIx : string; CallTime: TDateTime; Result: String; begin uri:=StrToJURI('content://call_log/calls'); cursor := SharedActivity.getContentResolver.query(uri, nil, nil,nil,nil); // CACHED_FORMATTED_NUMBER:=cursor.getColumnIndex(StringToJstring('CACHED_FORMATTED_NUMBER')); // CACHED_LOOKUP_URI:=cursor.getColumnIndex(StringToJstring('CACHED_LOOKUP_URI')); // CACHED_MATCHED_NUMBER:=cursor.getColumnIndex(StringToJstring('CACHED_MATCHED_NUMBER')); CACHED_NAME:=cursor.getColumnIndex( TJCallLog_Calls.JavaClass.CACHED_NAME ); // CACHED_NORMALIZED_NUMBER:=cursor.getColumnIndex(StringToJstring('CACHED_NORMALIZED_NUMBER')); // CACHED_NUMBER_LABEL:=cursor.getColumnIndex(StringToJstring('CACHED_NUMBER_LABEL')); // CACHED_NUMBER_TYPE:=cursor.getColumnIndex(StringToJstring('CACHED_NUMBER_TYPE')); // CACHED_PHOTO_ID:=cursor.getColumnIndex(StringToJstring('CACHED_PHOTO_ID')); // CONTENT_ITEM_TYPE:=cursor.getColumnIndex(StringToJstring('CONTENT_ITEM_TYPE')); // CONTENT_TYPE:=cursor.getColumnIndex(StringToJstring('CONTENT_TYPE')); // COUNTRY_ISO:=cursor.getColumnIndex(StringToJstring('COUNTRY_ISO')); // DATA_USAGE:=cursor.getColumnIndex(StringToJstring('DATA_USAGE')); DATE:=cursor.getColumnIndex( TJCallLog_Calls.JavaClass.DATE ); // DEFAULT_SORT_ORDER:=cursor.getColumnIndex(StringToJstring('DEFAULT_SORT_ORDER')); DURATION:=cursor.getColumnIndex( TJCallLog_Calls.JavaClass.DURATION ); // EXTRA_CALL_TYPE_FILTER:=cursor.getColumnIndex(StringToJstring('EXTRA_CALL_TYPE_FILTER')); // FEATURES:=cursor.getColumnIndex(StringToJstring('FEATURES')); // IS_READ:=cursor.getColumnIndex(StringToJstring('IS_READ')); // LIMIT_PARAM_KEY:=cursor.getColumnIndex(StringToJstring('LIMIT_PARAM_KEY')); // NEW:=cursor.getColumnIndex(StringToJstring('NEW')); // NUMBER:=cursor.getColumnIndex(StringToJstring('NUMBER')); // NUMBER_PRESENTATION:=cursor.getColumnIndex(StringToJstring('NUMBER_PRESENTATION')); // OFFSET_PARAM_KEY:=cursor.getColumnIndex(StringToJstring('OFFSET_PARAM_KEY')); // PHONE_ACCOUNT_COMPONENT_NAME:=cursor.getColumnIndex(StringToJstring('PHONE_ACCOUNT_COMPONENT_NAME')); // PHONE_ACCOUNT_ID:=cursor.getColumnIndex(StringToJstring('PHONE_ACCOUNT_ID')); // NUMBER_PRESENTATION:=cursor.getColumnIndex(StringToJstring('NUMBER_PRESENTATION')); // TRANSCRIPTION:=cursor.getColumnIndex(StringToJstring('TRANSCRIPTION')); // TYPEX:=cursor.getColumnIndex(StringToJstring('TYPE')); while (cursor.moveToNext) do begin // CACHED_FORMATTED_NUMBERx:=JStringToString(cursor.getString(CACHED_FORMATTED_NUMBER)); // CACHED_LOOKUP_URIx:=JStringToString(cursor.getString(CACHED_LOOKUP_URI)); // CACHED_MATCHED_NUMBERx:=JStringToString(cursor.getString(CACHED_MATCHED_NUMBER)); CACHED_NAMEx:=JStringToString(cursor.getString(CACHED_NAME)); // CACHED_NORMALIZED_NUMBERx:=JStringToString(cursor.getString(CACHED_NORMALIZED_NUMBER)); // CACHED_NUMBER_LABELx:=JStringToString(cursor.getString(CACHED_NUMBER_LABEL)); // CACHED_NUMBER_TYPEx:=JStringToString(cursor.getString(CACHED_NUMBER_TYPE)); // CACHED_PHOTO_IDx:=JStringToString(cursor.getString(CACHED_PHOTO_ID)); // CONTENT_ITEM_TYPEx:=JStringToString(cursor.getString(CONTENT_ITEM_TYPE)); // CONTENT_TYPEx:=JStringToString(cursor.getString(CONTENT_TYPE)); // COUNTRY_ISOx:=JStringToString(cursor.getString(COUNTRY_ISO)); // DATA_USAGEx:=JStringToString(cursor.getString(DATA_USAGE)); DATEx:=JStringToString(cursor.getString(DATE)); // DEFAULT_SORT_ORDERx:=JStringToString(cursor.getString(DEFAULT_SORT_ORDER)); DURATIONx:=JStringToString(cursor.getString(DURATION)); // EXTRA_CALL_TYPE_FILTERx:=JStringToString(cursor.getString(EXTRA_CALL_TYPE_FILTER)); // FEATURESx:=JStringToString(cursor.getString(FEATURES)); // IS_READx:=JStringToString(cursor.getString(IS_READ)); // LIMIT_PARAM_KEYx:=JStringToString(cursor.getString(LIMIT_PARAM_KEY)); // NEWx:=JStringToString(cursor.getString(NEW)); // NUMBERx:=JStringToString(cursor.getString(NUMBER)); // NUMBER_PRESENTATIONx:=JStringToString(cursor.getString(NUMBER_PRESENTATION)); // OFFSET_PARAM_KEYx:=JStringToString(cursor.getString(OFFSET_PARAM_KEY)); // PHONE_ACCOUNT_COMPONENT_NAMEx:=JStringToString(cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)); // PHONE_ACCOUNT_IDx:=JStringToString(cursor.getString(PHONE_ACCOUNT_ID)); // NUMBER_PRESENTATIONx:=JStringToString(cursor.getString(NUMBER_PRESENTATION)); // TRANSCRIPTIONx:=JStringToString(cursor.getString(TRANSCRIPTION)); // TYPEXx:=JStringToString(cursor.getString(TYPEX)); CallTime := StrToDateTime(DATEx); <- THIS DON'T WORK! Result := CACHED_NAMEx + ' ' + FormatDateTime('dd.mm.yyyy hh:mm:ss', CallTime) + ' ' + DURATIONx; ShowMessage(Result); end; 1 Share this post Link to post
Lars Fosdal 1792 Posted April 21, 2020 program Test; uses SysUtils, DateUtils; const USec: Int64 = 1587377791601; var dt: TDateTime; begin dt := UnixToDateTime(Usec); Writeln(FormatDateTime('yyyy.mm.dd hh:nn:ss,zzz', dt)); end. spits out 52272.01.01 03:26:41,000 Are you sure that you wrote an actual example value? Share this post Link to post
erva 2 Posted April 21, 2020 Yes, i get same like results in app with real data with several calls DATEx what comes from call_log. Share this post Link to post
erva 2 Posted April 21, 2020 I asked same question in Stackoverflow: https://stackoverflow.com/questions/61332432/delphi-getting-android-call-logs-date?noredirect=1#comment108504919_61332432 There's mentioned that value is number of millisecond since January 1, 1970, 00:00:00 GMT. This gets complicated.... Share this post Link to post
erva 2 Posted April 21, 2020 Solved the problem. Code is not "optimised" but works: CallTimeDouble := StrToInt64(DATEx) / 1000; //Gives seconds CallTimeDouble := CallTimeDouble / 60; //Gives Minutes CallTimeDouble := CallTimeDouble / 60; //Gives hours CallTimeDOuble := CallTimeDouble / 24; //Gives dates CallTimeDouble := CallTimeDouble + 25569; //01.01.1970 - 30.12.1899 CallTimeDouble := CallTimeDouble + 0.125; //Added +3h to GMT, Finland Result := CACHED_NAMEx + ' ' + NUMBERx + ' ' + FormatDateTime('dd.mm.yyyy hh:mm:ss', CallTimeDouble) + ' ' + DURATIONx; ShowMessage(Result); Share this post Link to post
Lars Fosdal 1792 Posted April 21, 2020 Aha - I assumed the UnixToDateTime did milliseconds - but it also requires seconds. If you change your code to CallTimeDouble := UnixToDateTime(Round(StrToInt64(DATEx)/1000), false); you should get local time, which for you is UTC + 3 ? So '1587377791601' is 2020.04.20 13:16:32,000 1 Share this post Link to post