user48623: What is the shortest/most elegant way (i.e. use existing lib functions) to parse a string in the form of 20180810T143000Z to a time_t? Note that the literal always represents a UTC timestamp.
I started parsing the string and assigning values to a struct tm *tm in order to do a mktime(tm) at the end. That feels overly complicated, though.

user48623: For the sake of completeness here's my "answer" working with Strings rather than char[].
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);
}


user30198: This is not complete without sscanf.
I took the sketch by @Juraj and declared seperate integers to be sure that every %d would match with an integer.
#include <Time.h>

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() {
}

Marcel Stör, there are now four good solutions. In my opinion they are equally good.

user37622: Alternative to my first answer would be to use standard C functions from time.h and sscanf. C function strptime can't parse the timestamp without delimiters. But sscanf can parse your input. 
#include <time.h>

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() {
}

In AVR "%02hhd" must be used because the corresponding members in struct tm are int8_t.

user37622: #include <Time.h>

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() {

}

You can install TimeLib in Library Manager. It works on all Arduino platforms.

user37523: Here is yet another way to convert the time stamp string to time_t. There are several great answers here already, but you may want to compare binary file sizes. This sketch's is 3884 bytes (IDE Version 1.0.6.2, GCC 4.2.1).
#include <Time.h>
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(){}


user4143: Parsing the string really is the only way. However there are many ways of doing it.
My preferred method is to first check that the format is correct, by looking for the T and Z being in the right place:
if (timeString[8] == 'T' && timeString[15] == 'Z') {
    ... parse in here
}

And the parsing is just making numbers with multiplication:
int year = (timeString[0] - '0') * 1000 +
           (timeString[1] - '0') * 100 +
           (timeString[2] - '0') * 10 +
           (timeString[3] - '0');

You can clean things up with a macro if you like:
#define NUM(off, mult) ((timeString[(off)] - '0') * (mult))

Then:
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);

And then, yes, put them in a struct tm (or directly assign them calculation results without using the intermediate variables) and call mktime(). 

48623: <p>What is the shortest/most elegant way (i.e. use existing lib functions) to parse a string in the form of <code>20180810T143000Z</code> to a <code>time_t</code>? Note that the literal always represents a UTC timestamp.</p>

<p>I started parsing the string and assigning values to a <code>struct tm *tm</code> in order to do a <code>mktime(tm)</code> at the end. That feels overly complicated, though.</p>
 48623: <p>For the sake of completeness here's my "answer" working with <code>String</code>s rather than <code>char[]</code>.</p>

<pre><code>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(&amp;tm);
}
</code></pre>
 30198: <p>This is not complete without sscanf.</p>

<p>I took the sketch by @Juraj and declared seperate integers to be sure that every %d would match with an integer.</p>

<pre><code>#include &lt;Time.h&gt;

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", &amp;yr, &amp;mnth, &amp;d, &amp;h, &amp;m, &amp;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() {
}
</code></pre>

<p>Marcel Stör, there are now four good solutions. In my opinion they are equally good.</p>
 37622: <p>Alternative to my first answer would be to use standard C functions from time.h and sscanf. C function strptime can't parse the timestamp without delimiters. But sscanf can parse your input. </p>

<pre><code>#include &lt;time.h&gt;

void setup() {

  Serial.begin(115200);

  const char* buff = "20180810T143000Z";

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

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

void loop() {
}
</code></pre>

<p>In AVR "%02hhd" must be used because the corresponding members in struct tm are int8_t.</p>
 37622: <pre><code>#include &lt;Time.h&gt;

void setup() {

  Serial.begin(115200);

  char buff[] = "20180810T143000Z";
  for (int i = 0; i &lt; sizeof(buff); i++) {
    buff[i] = buff[i] - '0';
  }
  int yr = buff[0] * 1000 + buff[1] * 100 + buff[2] * 10 + buff[3];
  if (yr &gt; 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() {

}
</code></pre>

<p>You can install TimeLib in Library Manager. It works on all Arduino platforms.</p>
 37523: <p>Here is yet another way to convert the time stamp string to time_t. There are several great answers here already, but you may want to compare binary file sizes. This sketch's is 3884 bytes (IDE Version 1.0.6.2, GCC 4.2.1).</p>

<pre><code>#include &lt;Time.h&gt;
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(){}
</code></pre>
 4143: <p>Parsing the string really is the only way. However there are many ways of doing it.</p>

<p>My preferred method is to first check that the format is correct, by looking for the T and Z being in the right place:</p>

<pre><code>if (timeString[8] == 'T' &amp;&amp; timeString[15] == 'Z') {
    ... parse in here
}
</code></pre>

<p>And the parsing is just making numbers with multiplication:</p>

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

<p>You can clean things up with a macro if you like:</p>

<pre><code>#define NUM(off, mult) ((timeString[(off)] - '0') * (mult))
</code></pre>

<p>Then:</p>

<pre><code>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);
</code></pre>

<p>And then, yes, put them in a <code>struct tm</code> (or directly assign them calculation results without using the intermediate variables) and call <code>mktime()</code>. </p>
