Der C-Sprachcode konvertiert die Zeitstempelzeichenfolge in ein Datums- und Zeitformat und testet die Methode, um Fehler zu beheben

Ein Zeitstempel ist ein numerisches Format, das zur Darstellung von Datum und Uhrzeit verwendet wird. Die Länge und Einheiten von Zeitstempeln variieren je nach Programmiersprache:

C: In Sekunden, der aktuelle Zeitstempel ist 10 Ziffern.

Python: Millisekunden in Sekunden und auf 7 Dezimalstellen genau. Der ganzzahlige Teil des aktuellen Zeitstempels ist 10 Ziffern und Millisekunden sind auf 7 Dezimalstellen genau.

JavaScript: Der Zeitstempel beträgt derzeit 13 Stellen in Millisekunden.

Obwohl Zeitstempel für die interne Zeitverarbeitung in Computern sehr praktisch sind, sind sie für Menschen nicht intuitiv. Bei der täglichen Programmierarbeit stoßen wir häufig auf Situationen, in denen wir Zeitstempel in Datums- und Zeitformate konvertieren müssen, um die Datenverarbeitung, Analyse und Berichterstellung zu erleichtern.

Verwendung der time.h-Bibliothek der C-Sprache

Verwenden Sie die Bibliothek time.h in der Sprache C, um die Konvertierung der Zeitstempelzeichenfolge in das Datums-/Uhrzeitformat durchzuführen. Unten finden Sie den Democode, der die Funktion „localtime“ verwendet, um den Zeitstempel in eine tm-Struktur umzuwandeln, und ihn dann mithilfe von sprintf in eine Datums-/Uhrzeitzeichenfolge formatiert.

char* timestamp_to_datetime(long long timestamp){
    int timestamp_length = snprintf(NULL, 0, "%lld", timestamp);
    static char result[20];
    struct tm *tm;
    time_t time_seconds;
    tm = localtime(&time_seconds);
    // 容错处理
    if (tm == NULL) {
        perror("localtime");
        result[0] = '\0';
        return result;
    }

    // 时间戳的前10位数转换为日期和时间
    sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
    return result;
}

Meine Idee ist: Verarbeiten Sie für einen von JavaScript generierten 13-stelligen Zeitstempel zunächst die ersten 10 Ziffern, um Datum und Uhrzeit umzuwandeln, und fügen Sie dann die letzten 3 Ziffern als Millisekunden zum Datum und zur Uhrzeit hinzu. Zeitstempel, die kleiner als 13 Ziffern sind, werden direkt konvertiert. Daher ist es notwendig, die Länge der Zeitstempelzeichenfolge zu bestimmen. Die Funktion wird wie folgt geändert:

char* timestamp_to_datetime(long long timestamp){
    int timestamp_length = snprintf(NULL, 0, "%lld", timestamp);
    static char result[20];
    struct tm *tm;
    time_t time_seconds;
    // 如果时间戳长度为13,则取前10位数为时间戳
    time_seconds = timestamp_length == 13 ? (time_t)(timestamp / 1000) : (time_t)(timestamp);
    tm = localtime(&time_seconds);
    // 容错处理
    if (tm == NULL) {
        perror("localtime");
        result[0] = '\0';
        return result;
    }

    // 时间戳的前10位数转换为日期和时间
    sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);

    // 如果时间戳长度为13,则将11~13位数作为毫秒数
    if (timestamp_length == 13) {
        char ms[4];
        sprintf(ms, "%lld", timestamp % 1000);
        strcat(result, ms);
    }
    return result;
}

Als nächstes folgt der Code des Hauptprogramms, das den ersten über die Befehlszeile eingegebenen Parameter als Zeitstempelzeichenfolge empfängt:

int main(int argc, char *argv[]) {
    long long timestamp;
    char result[20];
    if (argc != 2) {
        printf("\n时间戳转换成日期时间。\n\n使用方法:%s <时间戳>\n\n注:时间戳长度不应该超过13位数字。\n", argv[0]);
        // 获取当前时间
        time(&timestamp);
        printf("\n当前时间戳:%lld\n", timestamp);
        sprintf(result, "%s", timestamp_to_datetime(timestamp));
        printf("时间戳转换为日期时间是:%s\n", result);
        return 1;
    }

    // 从命令行参数获取第一个参数作为时间戳字符串
    timestamp = atoll(argv[1]); 
    int timestamp_length = strlen(argv[1]);
    printf("你输入的时间戳是:%lld\n长度为%d位数。\n", timetamp, timestamp_length);

    result = timestamp_to_datetime(timestamp);
    if (result[0]){
        printf("时间戳转换为日期时间是:%s\n", result);
    }
    return 0;
}

Das Programm ist grundsätzlich geschrieben. Aber dieser Code hat viele Fehler:

Fehler Nr. 1: Rechtmäßigkeit der Eingabeparameter

Erstens wird nicht überprüft, ob die Eingabeparameter zulässig sind. Beispielsweise muss die Eingabezeichenfolge eine Zahl sein. Wenn die Eingabeparameter mit Buchstaben oder anderen Symbolen gemischt sind, kann die Localtime-Funktion nicht konvertieren und meldet direkt einen Fehler und beendet die Funktion Programm.

In Python gibt es eine Methode, um zu überprüfen, ob eine Zeichenfolge ausschließlich aus Ziffern besteht: string.isdigit(). Die Methode ist einfach und effektiv. Obwohl die C-Sprache auch über isdigit() verfügt, ist diese nur für die Prüfung verantwortlich, ob ein Zeichen eine Ziffer ist, und nicht für die Beurteilung einer Zeichenfolge. In der C-Sprachbibliothek gibt es keine vorgefertigte Funktion, um zu prüfen, ob eine Zeichenfolge eine Ziffer ist Ich muss eines von Hand schreiben:

// 检查字符串是否全是数字
int isStringAllDigits(const char *str) {
    for (int i = 0; str[i] != '\0'; i++) {
        if (!isdigit((unsigned char)str[i])) {
            return 0; // 只要检测到非数字的字符串就直接返回0
        }
    }
    return 1; // 全是数字的话返回1
}

Oder schreiben Sie etwas Fortgeschritteneres und verwenden Sie Zeiger und While-Schleifen, was prägnanter und effizienter ist:

// 检查字符串是否全是数字,高级写法:
int isStringAllDigits(const char *str) {
    while (*str)
        if (!isdigit((unsigned char)(*str++)))
            return 0; 
    return 1;
}

Fehler Nr. 2: Überprüfung der Gültigkeit der Eingabeparametergrenzen.

Die eingegebene Zeitstempelzeichenfolge darf nicht mehr als 13 Ziffern lang sein.

    if (timestamp_length > 13) {
        printf("长度不正确!注:时间戳长度不应该超过13位数字。\n\n");
        return 1;
    }

Nach dem Kompilieren und Ausführen des Tests haben wir festgestellt, dass eine lokale Zeitfehlermeldung zurückgegeben wird, wenn der Zeitstempel eine große Zahl mit 11 oder 12 Ziffern ist, die darauf hinweist, dass der Wert die Grenze überschritten hat.

Überprüfen Sie die relevanten Dokumente ( localtime, _localtime32, _localtime64 | Microsoft Learn ) und erfahren Sie Folgendes: Die von localtime zurückgegebene maximale Zeit ist 23:59:59 am 31. Dezember 3000, dann ist der entsprechende Zeitstempel 32535158399.

Aber nach meinem Debuggen können Datum und Uhrzeit immer noch ausgegeben werden, wenn der Zeitstempel größer als 32535158399 ist:

Solange die Zeitstempellänge weniger als 13 beträgt, darf der maximale Zeitstempelwert 32536799999 nicht überschreiten und der maximale Datumswert kann 15:59:59 am 19. Januar 3001 erreichen.

Daher müssen Sie einen Code hinzufügen, um zu überprüfen, ob der Parameter die Grenze überschreitet:

    if (timestamp>32536799999 && timestamp<1000000000000){
        printf("注:%d位数的数值不能大于32536799999。\n你可以尝试输入13位数的时间戳。", timestamp_length);
        return 1;
    }

Fehler Nr. 3: Der Eingabeparameter ist tatsächlich eine Zahl, aber es handelt sich um eine lange Zahlenfolge, die mit 0 beginnt.

Diese Situation wird leicht übersehen. Wenn Sie eine Zahl eingeben, die mit 0 beginnt: 001, 0123456789, müssen Sie zuerst die überschüssige 0 entfernen.

Soll ich die Zeichenfolge zuerst konvertieren, vom Anfang an auf Nicht-Null-Positionen prüfen, dann bis zum Ende abfangen und sie schließlich in eine Zahl umwandeln?

Das ist nicht so problematisch. Die C-Sprache bietet eine Reihe flexibler Konvertierungsfunktionen, darunter: atoll() , das Zeichenfolgen in Variablen vom Typ Integer formatiert:

    timestamp = atoll(timestamp_str); 

Diesmal werden die zusätzlichen Nullen davor entfernt. Aber es gibt ein Problem:

Wenn Sie eine lange Zahl eingeben, die mit 0 beginnt, wie zum Beispiel: 00000000000009876543210,

Die Zeitstempelvariable ist 9876543210, nachdem sie von atoll(timestamp_str) konvertiert wurde.

Die Zeichenfolge timestamp_str speichert „00000000000009876543210“ mit einer Länge von 23.

Wenn beurteilt wird, ob die Länge von timestamp_str 13 nicht überschreitet, wird gemäß der Beurteilung des obigen Codes direkt ausgegeben: Wenn die Länge 13 überschreitet, wird das Programm beendet.

Daher sollte die Länge des Zeitstempels beurteilt werden.

Da der Typ des Zeitstempels long long ist, können Sie strlen(timestamp) nicht direkt verwenden, um seine Länge abzurufen. Sie können ihn nur mit der Funktion snprintf abrufen:

    // 如果输入值为0开头,如:0000123456789,则必须先用atoll转成长数值,去除前面所有0
    timestamp = atoll(argv[1]);   
    int timestamp_length = snprintf(NULL, 0, "%lld", timestamp);
    printf("你输入的时间戳是:%lld\n长度为%d位数。\n", timestamp, timestamp_length);

    if (timestamp_length > 13) {
        printf("长度不正确!注:时间戳长度不应该超过13位数字。\n\n");
        return 1;
    }

Auf diese Weise kann selbst die Eingabe einer langen Zahl ordnungsgemäß verarbeitet werden, ohne dass eine Ortszeitfehlermeldung zurückgegeben wird.

Fehler Nr. 4: Problem mit der Ausgabecodepage

Das mit C-Code kompilierte und ausgeführte .exe-Programm gibt Text standardmäßig im UTF-8-Format aus. Die entsprechende Codepage für UTF-8 ist 65001.

Das Standardformat der Befehlszeile des Windows-Systems ist GBK und die Codepage ist 936.

Wenn der obige Code kompiliert und in der Windows-Befehlszeile ausgeführt wird, werden alle chinesischen Zeichen als verstümmelte Zeichen angezeigt. Zur Anpassung an die Windows-Befehlszeile sollte im C-Code im Hauptprogramm eine Zeile eingefügt werden, um die Codepage auf UTF-8 zu setzen, um sicherzustellen, dass der Ausgabetext korrekt angezeigt wird.

#include <windows.h>

。。。

int main(int argc, char *argv[]) {
    // 切换至UTF-8(65001)环境输出
    int codePage = GetConsoleOutputCP();
    SetConsoleOutputCP(CP_UTF8); 
    。。。
}

Wenn es sich um ein Linux-System handelt, ist dieser Schritt nicht erforderlich, da die Standardzeichenkodierung von Linux UTF-8 ist und es keine Windows.h-Bibliotheksdatei gibt.

Okay, nachdem ich die Eingabezulässigkeit überprüft und die Variablengrenzen oben überprüft habe, sind die Fehler im Code grundsätzlich behoben. Das Folgende ist der vollständige Code.

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <windows.h>

// 检查字符串是否全是数字
int isStringAllDigits(const char *str) {
    while (*str)
        if (!isdigit((unsigned char)(*str++)))
            return 0; 
    return 1;
}


char* timestamp_to_datetime(long long timestamp){
    int timestamp_length = snprintf(NULL, 0, "%lld", timestamp);
    static char result[20];
    struct tm *tm;
    time_t time_seconds;
    // 如果时间戳长度为13,则取前10位数为时间戳
    time_seconds = timestamp_length == 13 ? (time_t)(timestamp / 1000) : (time_t)(timestamp);
    tm = localtime(&time_seconds);
    // 容错处理
    if (tm == NULL) {
        perror("localtime");
        result[0] = '\0';
        return result;
    }

    // 时间戳的前10位数转换为日期和时间
    sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);

    // 如果时间戳长度为13,则将11~13位数作为毫秒数
    if (timestamp_length == 13) {
        char ms[4];
        sprintf(ms, "%lld", timestamp % 1000);
        strcat(result, ms);
    }
    return result;
}


int main(int argc, char *argv[]) {
    // 切换至UTF-8(65001)环境输出
    int codePage = GetConsoleOutputCP();
    SetConsoleOutputCP(CP_UTF8); 
    long long timestamp;
    char result[20];
    if (argc != 2) {
        printf("\n时间戳转换成日期时间。\n\n使用方法:%s <时间戳>\n\n注:时间戳长度不应该超过13位数字。\n", argv[0]);
        // 获取当前时间
        time(&timestamp);
        printf("\n当前时间戳:%lld\n", timestamp);
        sprintf(result, "%s", timestamp_to_datetime(timestamp));
        printf("时间戳转换为日期时间是:%s\n", result);
        SetConsoleOutputCP(codePage);
        return 1;
    }

    // 从命令行参数获取第一个参数作为时间戳字符串
    // 判断输入参数是否全是数字
    if (!isStringAllDigits(argv[1])) {
        printf("输入不合法。请输入由数字组成的时间戳。\n");
        SetConsoleOutputCP(codePage);
        return 1;
    }

    // 如果输入值为0开头,如:0000123456789,则必须先用atoll转成长数值,去除前面所有0
    timestamp = atoll(argv[1]);   
    int timestamp_length = snprintf(NULL, 0, "%lld", timestamp);
    printf("你输入的时间戳是:%lld\n长度为%d位数。\n", timestamp, timestamp_length);

    if (timestamp_length > 13) {
        printf("长度不正确!注:时间戳长度不应该超过13位数字。\n\n");
        SetConsoleOutputCP(codePage);
        return 1;
    }
        
    if (timestamp>32536799999 && timestamp<1000000000000){
        printf("注:%d位数的数值不能大于32536799999。\n你可以尝试输入13位数的时间戳。\n", timestamp_length);
        SetConsoleOutputCP(codePage);
        return 1;
    }
    sprintf(result, "%s", timestamp_to_datetime(timestamp));
    if (result[0]){
        printf("时间戳转换为日期时间是:%s\n", result);
        SetConsoleOutputCP(codePage);
    }
    return 0;
}

Screenshot der laufenden Ergebnisse:

Guess you like

Origin blog.csdn.net/Scott0902/article/details/134005274