20180810T143000Z уақытын анықтау әдісі

20180810T143000Z түріндегі жолды time_t түріне талдау үшін ең қысқа/ең талғампаз әдіс дегеніміз (яғни, бар lib функцияларын пайдалану) қандай? Айталық, әрқашан UTC уақыт белгісін білдіреді.

Жолды талдап, соңында mktime (tm) жасау үшін struct tm * tm мәндерін тағайындадым. Бірақ бұл өте күрделі.

0
Сіз қай уақытта кітапхананы пайдаланасыз? Әрбір қажет таңбаны массив индексі бар буферге көшіріп, оны жыл, ай, күн, сағат, минутқа айналдыратын болар едім. Содан кейін кітапхананы 1970 жылдан бастап секундтар санына айналдыру үшін пайдаланатын боламын. Менің көзқарасым бойынша өте күрделі емес. Сіз әлі күнге дейін бар екенін көрсете аласыз ба? sscanf жұмыс істей алады, бірақ кейбіреулер бұл талғампаз функция емес деп ойлайды.
қосылды автор Standback, көзі

6 жауаптар

Жолды шынымен талдау - бұл жалғыз жол. Алайда, оны орындаудың көптеген жолдары бар.

Менің артықшылықты әдіс - алдымен T және Z-ді дұрыс жерде іздеу арқылы пішімнің дұрыс екендігін тексеру.

if (timeString[8] == 'T' && timeString[15] == 'Z') {
    ... parse in here
}

Сараптау тек сандарды көбейту арқылы ғана жасайды:

int year = (timeString[0] - '0') * 1000 +
           (timeString[1] - '0') * 100 +
           (timeString[2] - '0') * 10 +
           (timeString[3] - '0');

Қажет болса, макростармен тазалауға болады:

#define NUM(off, mult) ((timeString[(off)] - '0') * (mult))

Сонда:

int year =   NUM(0, 1000) + NUM(1, 100) + NUM(2, 10) + NUM(3, 1);
int month =  NUM(4, 10)   + NUM(5, 1);
int day =    NUM(6, 10)   + NUM(7, 1);
int hour =   NUM(9, 10)   + NUM(10, 1);
int minute = NUM(11, 10)  + NUM(12, 1);
int second = NUM(13, 10)  + NUM(14, 1);

Содан кейін, иә, оларды struct tm (немесе аралық айнымалы мәндерді пайдаланбастан оларды есептеу нәтижелерін тікелей тағайындаңыз) және mktime() деп шақырыңыз.

2
қосылды
@ MarcelStör Sure - егер сіз мұны істегіңіз келсе.
қосылды автор Majenko, көзі
Мен сізге айта алмаймын. Бұл сіздің бағдарламаңыздың қалған бөлігіне байланысты. Жауап «ештеңе» болмауы мүмкін немесе «пайдаланушыға айту», «жаңа уақыт белгісін сұрастыру» немесе басқа да көптеген нәрселер болуы мүмкін.
қосылды автор Majenko, көзі
@Juraj Yeah, бірақ сіз жауапта жауап берген жоқсыз, тек код блогы;)
қосылды автор Majenko, көзі
@ Маженко өкінішті, мен біраз ерекше емеспін. Мен Arduino-мен әлі де танысмын (қалай айтуға болады). Мен айтқанымдай, көптеген басқа ортада/платформаларда таныс болсам, мен алып тастай алатын шығармын. Осылайша, мен -1-ге қайтып оралып, бұл функциядан тыс жұмыс істеймін деп ойлаймын.
қосылды автор Krunal Hingu, көзі
«алдымен пішімнің дұрыс екенін тексеріңіз» - жарамды нүкте, бірақ else бөлімінде не істедіңіз?
қосылды автор Krunal Hingu, көзі

Уақытша мөртабанның жолын time_t мәніне айналдырудың тағы бір жолы. Мұнда бірнеше үлкен жауап бар, бірақ екілік файл өлшемдерін салыстыру қажет болуы мүмкін. Бұл нобай 3884 байт (IDE 1.0.6.2 нұсқасы, GCC 4.2.1).

#include 
TimeElements myTimeElements;
char timeString[] = "20180810T143000Z";

void setup(){

  Serial.begin(9600);

  myTimeElements.Year = CalendarYrToTm((timeString[0] - '0') * 1000 + (timeString[1] - '0') * 100 + (timeString[2] - '0') * 10 + (timeString[3] - '0'));
  myTimeElements.Month = (timeString[4] - '0') * 10 + (timeString[5] - '0');
  myTimeElements.Day = (timeString[6] - '0') * 10 + (timeString[7] - '0');
  myTimeElements.Hour = (timeString[9] - '0') * 10 + (timeString[10] - '0');
  myTimeElements.Minute = (timeString[11] - '0') * 10 + (timeString[12] - '0');
  myTimeElements.Second = (timeString[13] - '0') * 10 + (timeString[14] - '0');

 //Assemble time elements into time_t.
  time_t t = makeTime(myTimeElements);

 //Print out the contents of "t" one "piece" at a time using the "time_t" functions.
  Serial.println(year(t));
  Serial.println(month(t));
  Serial.println(day(t));
  Serial.println(hour(t));
  Serial.println(minute(t));
  Serial.println(second(t));

}

void loop(){}
1
қосылды

Бұл sscanfсіз толық емес.

Мен @Juraj нобайын алдым және әрбір% d бүтін санмен сәйкес келетініне сенімді болу үшін бөлек бүтін сандарды жарияладым.

#include 

void setup() {

  Serial.begin(115200);

  char buff[] = "20180810T143000Z";

  TimeElements tm;

  int yr, mnth, d, h, m, s;
  sscanf( buff, "%4d%2d%2dT%2d%2d%2dZ", &yr, &mnth, &d, &h, &m, &s);

  tm.Year = yr - 1970;
  tm.Month = mnth;
  tm.Day = d;
  tm.Hour = h;
  tm.Minute = m;
  tm.Second = s;

  time_t t = makeTime(tm);

  sprintf(buff, "%02d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t));

  Serial.println(buff);
}

void loop() {
}

Марсел Стор, қазір төрт жақсы шешім бар. Менің ойымша, олар бірдей жақсы.

1
қосылды
#include 

void setup() {

  Serial.begin(115200);

  char buff[] = "20180810T143000Z";
  for (int i = 0; i < sizeof(buff); i++) {
    buff[i] = buff[i] - '0';
  }
  int yr = buff[0] * 1000 + buff[1] * 100 + buff[2] * 10 + buff[3];
  if (yr > 99)
    yr = yr - 1970;
  else
    yr += 30;
  TimeElements tm;
  tm.Year = yr;
  tm.Month = buff[4] * 10 + buff[5];
  tm.Day = buff[6] * 10 + buff[7];
 //8 T
  tm.Hour = buff[9] * 10 + buff[10];
  tm.Minute = buff[11] * 10 + buff[12];
  tm.Second = buff[13] * 10 + buff[14];

  time_t t = makeTime(tm);

  sprintf(buff, "%02d%02d%02d %02d%02d%02d", year(t), month(t), day(t), hour(t), minute(t), second(t));

  Serial.println(buff);

}

void loop() {

}

TimeLib бағдарламасын Кітапхана менеджеріне орнатуға болады. Ол барлық Arduino платформаларында жұмыс істейді.

1
қосылды
buff [i ++] * 10 + buff [i ++] ішінде i ++ бағалау тәртібі анықталмады. Ол компиляторлық нұсқалар мен параметрлердің қандай да бір комбинациясымен күткендегідей жұмыс істей алады және келесіде сәтсіздікке ұшырайды. gcc 5.4 «i» операциясы «анықталмаған болуы мүмкін» деп ескертеді. Мұны дұрыс жолмен tm.Month = buff [i ++] * 10; tm.Month + = buff [i ++]; .
қосылды автор Sprogz, көзі
@ MarcelStör: tm.Month үшін жазғанымның барлығы i ++ бірдей өрнекте бірнеше рет пайда болған әрбір данаға жарамды.
қосылды автор Sprogz, көзі
«Компиляторды бағалауға ешқандай себеп жоқ [...]»: оларды күткен тәртіпте бағалауға ешқандай себеп жоқ! C ++-та қате болжамдар жасамай тұрып, жүйелі қадамдар туралы біліңіз. Айта кету керек, «алдыңғы және келесі кезектегі нүктенің арасында объектілердің өрнектің бағалануы арқылы өзгертілген оның сақталған мәні болуы керек».
қосылды автор Sprogz, көзі
i ++ параметрін тұрақты мәндерге өзгертеді. (Жыл дәрежесі №4. yabba dabba doo)
қосылды автор Juraj, көзі
бұл жағдайда i ++-ді қолдану жақсы. компиляторда кейбір iшкөрулерді i ++-мен кейінірек сөйлемдегі кейбір тұжырымдамалар алдында i ++ бұрынғы сөйлемде бағалауға ешқандай себеп жоқ. Мен оны өзгерте аламын. Мен ескертуді көрдім, бірақ бұған уақыт аз болды.
қосылды автор Juraj, көзі
@ MarcelStör, мен Эдгарның түсініктемесін оқып бердім, бірақ бұл кодекс кейбір үзінді емес, бірақ толық жұмыс мысал. Маған ұнамайды, тестілеусіз редакциялау. Мен қазір сынап көре алмаймын.
қосылды автор Juraj, көзі
@EdgarBonet Мен білемін, жалпы мағынасын береді. Сондықтан редакцияны ұсынды. Ақыр аяғында, көптеген сызықтар шын мәнінде зардап шеккендіктен, ол қабылданбады.
қосылды автор Krunal Hingu, көзі
@EdgarBonet рахмет, мен бұл өзгерісті ұсындым: arduino.stackexchange.com/review/suggested-edits/38715
қосылды автор Krunal Hingu, көзі
Иә, мен strptime -қа қарадым, бірақ ол бөлгіштерді жұмыс істемейтін шығар. Сондықтан мен тіпті тырысты.
қосылды автор Krunal Hingu, көзі

Алғашқы жауапыма баламалы уақыт C және Sscanf стандартты функцияларын қолдануға болады. C функциясы strptime уақыт белгісін шектегіштермен бөліп шығара алмайды. Бірақ sscanf сіздің кірісіңізді талдай алады.

#include 

void setup() {

  Serial.begin(115200);

  const char* buff = "20180810T143000Z";

  tm tms;
  sscanf(buff, "%04d%02d%02dT%02d%02d%02d", &(tms.tm_year), &(tms.tm_mon), &(tms.tm_mday), &(tms.tm_hour), &(tms.tm_min), &(tms.tm_sec));
  tms.tm_year -= 1900;
  tms.tm_mon -= 1;
  tms.tm_isdst = 0;
  time_t t = mktime(&tms);

  Serial.println(ctime(&t));
}

void loop() {
}

AVR «% 02hhd» қолданылуы керек, себебі struct tm ішінде тиісті мүшелері int8_t болады.

1
қосылды
% D бүтін сан үшін, сондай-ақ avr микроконтроллер үшін. Айырмашылық, TimeLib TimeElements бүтін сандарды емес, байттарды пайдаланбайды.
қосылды автор Standback, көзі
Иә, C уақытында tm_year және басқа элементтер барлық бүтін сандар. Сондай-ақ, авр микроконтроллер үшін% d бүтін санға сәйкес келеді. % D 2 немесе 4 байт айнымалы емес, «int» деп күтеді.
қосылды автор Standback, көзі
Мен оны әртүрлі жолдармен әртүрлі деректермен қолданып көрдім, arduino 1.8.5-ді пайдалана отырып, арауино. 'Int' - екі байт, «қысқа» - екі байт және «қысқа қысқа» int жоқ. «% D» пішімі «int» және «% hd» сияқты жұмыс істейді, «% d» сияқты. «% Hhd» пішімі қол қойылған байтты оқиды. Барлығын есіме түсіремін, ештеңе жоқ. Егер нобаймен дұрыс екеніңізді дәлелдейтін болсаңыз, онда бұл үшін жаңа тақырыпты бастауға болады ма?
қосылды автор Standback, көзі
Енді көремін, avr үшін tm int8_t және int16_t элементтері бар. Кешіріңіз, олар шынымен де avr үшін бүтін сандар емес. Мен мұны білмедім. Рахмет. Сіз sscanf ішіндегі% d «int» үшін avr? Сіз соңғы сөйлемді шатастырып тастадыңыз.
қосылды автор Standback, көзі
AVR арналған% d sprintf үшін жұмыс істейді, бірақ sscanf hh жоқ дұрыс оқиды. сынап көріңіз
қосылды автор Juraj, көзі
@Jot, бұл C time.h
қосылды автор Juraj, көзі
@Jot, tm struct мүшелерін sscanf параметрлері ретінде қолданғанда ғана. Ескерту '% d' типі 'int *' түріндегі дәлелді күтуде, бірақ 4 дәлелі 'int8_t * {aka signed char *}' түріне ие. және сканерленген мәндер дұрыс емес. Тұрақты int айнымалы кезде hh қажет емес.
қосылды автор Juraj, көзі
AVRде int8_t tm_hour бар
қосылды автор Juraj, көзі
Мен hh пайдаланды, өйткені компилятор туралы ескерту ол int8_t екенін және дұрыс деректерді алуға көмектесті. Мен уақытты аштым, бірақ бұл самд үшін немесе эпс үшін болды, және int болды. Менің шектеулі уақытым болды, сондықтан оны одан әрі зерттемедім. Әрине% d - int үшін. Мен интенсивті тексердім және жазбаны жойдым. Сонда мен tm-де шынымен tm-да unt8_t екенін білдім.
қосылды автор Juraj, көзі

Толықтыру үшін мұнда char [] емес, String смен жұмыс істейтін менің «жауап» болады.

time_t convertToTime(String calTimestamp) {
  struct tm tm;
  Serial.println("Parsing " + calTimestamp);
  String year = calTimestamp.substring(0, 4);
  String month = calTimestamp.substring(4, 6);
  if (month.startsWith("0")) {
    month = month.substring(1);
  }
  String day = calTimestamp.substring(6, 8);
  if (day.startsWith("0")) {
    month = day.substring(1);
  }
  tm.tm_year = year.toInt() - 1900;
  tm.tm_mon = month.toInt() - 1;
  tm.tm_mday = day.toInt();
  tm.tm_hour = calTimestamp.substring(9, 11).toInt();
  tm.tm_min = calTimestamp.substring(11, 13).toInt();
  tm.tm_sec = calTimestamp.substring(13, 15).toInt();
  return mktime(&tm);
}
1
қосылды
Әбден мүмкін. String әдісі c_str() ішкі кодты қайтарады char * , сондықтан ешқандай нақты айырбастау қажет емес.
қосылды автор Sprogz, көзі
Бұл жұмыс істеуі керек, бірақ substring() әдісіне әрбір шақыру үймедегі жаңа жолды бөледі. Егер сізде бос жады көп болса, бұл malloc() және free() бірнеше қоңыраулар өте тиімді емес.
қосылды автор Sprogz, көзі
Бұл нашар кедей үй. Мен мұны сезінемін ...
қосылды автор Majenko, көзі
@EdgarBonet Иә, білемін, нүкте алынды. Бұл функцияға берілген нәрсе HTTP жауапының readStringUntil() (ішінара) нәтижесі болып табылады. calTimestamp сөзін алдымен char [] түрлендіру үшін неғұрлым тиімді болар еді деп ойлаймын?
қосылды автор Krunal Hingu, көзі