The time_t artikel Wikipedia Artikel memberi petunjuk pada ini. Intinya adalah bahwa jenis time_ttidak dijamin dalam spesifikasi C.
Tipe time_tdata adalah tipe data dalam pustaka ISO C yang didefinisikan untuk menyimpan nilai waktu sistem. Nilai-nilai tersebut dikembalikan dari time()
fungsi perpustakaan standar . Tipe ini adalah typedef yang didefinisikan dalam header standar. ISO C mendefinisikan time_t sebagai tipe aritmatika, tetapi tidak menentukan tipe , rentang, resolusi, atau penyandian tertentu untuk itu. Juga tidak ditentukan adalah arti operasi aritmatika yang diterapkan pada nilai waktu.
Sistem Unix dan POSIX-compliant menerapkan time_ttipe sebagai a signed
integer(biasanya lebar 32 atau 64 bit) yang mewakili jumlah detik sejak dimulainya zaman Unix : tengah malam UTC 1 Januari 1970 (tidak termasuk detik kabisat). Beberapa sistem dengan benar menangani nilai waktu negatif, sementara yang lain tidak. Sistem yang menggunakan tipe 32-bit time_trentan terhadap masalah Tahun 2038 .
Perhatikan, bagaimanapun, bahwa nilai time_t biasanya hanya disimpan dalam memori, bukan pada disk. Sebagai gantinya, time_t dikonversi ke teks atau format portabel lainnya untuk penyimpanan persisten. Itu membuat masalah Y2038 menjadi tidak terlalu masalah.
11
@Heath: pada sistem tertentu, di mana orang yang sama membuat sistem operasi dan pustaka C, menggunakan time_tdalam struktur data pada disk dapat terjadi. Namun, karena filesystem sering dibaca oleh sistem operasi lain, itu akan konyol untuk mendefinisikan filesystem berdasarkan pada jenis tergantung implementasi. Sebagai contoh, sistem file yang sama dapat digunakan pada sistem 32-bit dan 64-bit, dan time_tmungkin berubah ukuran. Dengan demikian, filesystem perlu didefinisikan secara lebih tepat ("integer bertanda 32-bit yang memberikan jumlah detik sejak awal 1970, dalam UTC") daripada hanya sebagai time_t.
1
Sebagai catatan: artikel Wikipedia yang tertaut telah dihapus, dan sekarang diarahkan ke daftar time.hkonten. Artikel itu terhubung ke cppreference.com tetapi konten yang dikutip tidak ditemukan ...
Michał Górny
3
@ MichałGórny: Diperbaiki, selama artikel tidak dihapus, Anda selalu dapat melihat riwayat untuk menemukan versi yang benar.
Zeta
4
-1; klaim yang dikutip dari Wikipedia bahwa jaminan POSIX yang time_tditandatangani tidak benar. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… menyatakan bahwa berbagai hal harus berupa "tipe integer yang ditandatangani" atau "tipe integer yang tidak ditandatangani", tetapi time_thanya dikatakan bahwa itu "akan menjadi tipe integer" . Implementasi dapat membuat time_tunsigned dan masih kompatibel dengan POSIX.
Saya melihat keduanya typedef __int32_t __time_t;dan typedef __time_t time_t;dalam a FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386. Hasil Anda secara eksplisit diatur seperti itu di Linux (setidaknya pada 2.6.32-5-xen-amd64 dari Debian).
Mengapa mencari __time_tdan tidak time_tmenemukan jenis yang mendasarinya time_t? Menghilangkan langkah?
chux
@ chux-ReinstateMonica - OP mengatakan bahwa ia telah menemukan typedef dari time_t ke __time_t. Jawaban ini hanya menjawab pertanyaan yang diajukan tentang apakah __time_t didefinisikan sebagai. Tapi saya setuju bahwa untuk kasus generik (di mana time_t mungkin tidak diketikkan menjadi __time_t), Anda perlu grep untuk time_t pertama, dan kemudian mungkin grep lagi untuk apa yang kembali
Michael Firth
@MichaelFirth Cukup adil. Saya ingat kekhawatiran saya meskipun OP menemukan typedef __time_t time_t;, pemeriksaan kode di sekitarnya juga diperlukan untuk memastikan bahwa typedef sebenarnya digunakan dan bukan hanya bagian dari kompilasi bersyarat. typedef long time_t;mungkin telah ditemukan juga.
chux
30
Standar
William Brendel mengutip Wikipedia, tetapi saya lebih suka dari mulut kuda.
Tidak perlu untuk pipa dari gema juga:gcc -E -xc -include time.h /dev/null | grep time_t
rvighne
12
Jawabannya jelas khusus untuk implementasi. Untuk mengetahui secara pasti untuk platform / kompiler Anda, cukup tambahkan output ini di suatu tempat dalam kode Anda:
printf ("sizeof time_t is: %d\n",sizeof(time_t));
Jika jawabannya adalah 4 (32 bit) dan data Anda dimaksudkan untuk melampaui 2038 , maka Anda memiliki 25 tahun untuk memigrasi kode Anda.
Data Anda akan baik-baik saja jika Anda menyimpan data Anda sebagai string, meskipun itu sesuatu yang sederhana seperti:
FILE*stream =[stream file pointer that you've opened correctly];
fprintf (stream,"%d\n",(int)time_t);
Kemudian baca saja kembali dengan cara yang sama (fread, fscanf, dll menjadi int), dan Anda memiliki waktu offset zaman Anda. Solusi serupa ada di. Net. Saya melewati nomor zaman 64-bit antara sistem Win dan Linux tanpa masalah (melalui saluran komunikasi). Itu memunculkan masalah pemesanan byte, tapi itu topik lain.
Untuk menjawab pertanyaan paxdiablo, saya akan mengatakan bahwa itu dicetak "19100" karena program ini ditulis dengan cara ini (dan saya akui saya melakukannya sendiri di tahun 80-an):
time_t now;struct tm local_date_time;
now = time(NULL);// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now),sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);
The printfpernyataan mencetak string tetap "Tahun ini: 19" diikuti dengan string nol-empuk dengan "tahun sejak tahun 1900" (definisi tm->tm_year). Pada tahun 2000, nilai itu adalah 100, jelas. "%02d"bantalan dengan dua nol tetapi tidak terpotong jika lebih dari dua digit.
Cara yang benar adalah (ubah hanya ke baris terakhir):
printf ("Year is: %d\n", local_date_time.tm_year +1900);
Anda mungkin harus menggunakan %zupenentu format untuk memformat size_tnilai (seperti yang dihasilkan oleh sizeof), karena mereka tidak ditandatangani ( u) dan dengan panjang size_t ( z) ·
Adrian Günter
... atau gunakan printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));dan hindari zmasalah ini.
chux
6
Di bawah Visual Studio 2008, itu default ke __int64kecuali Anda mendefinisikan _USE_32BIT_TIME_T. Anda lebih baik berpura-pura tidak tahu apa itu didefinisikan, karena itu dapat (dan akan) berubah dari platform ke platform.
Itu biasanya berhasil, tetapi jika program Anda dimaksudkan untuk melacak hal-hal yang akan terjadi 30 tahun dari sekarang, cukup penting bahwa Anda tidak memiliki time_t 32-bit yang sudah ditandatangani.
Rob Kennedy
4
@Rob, bah, tinggalkan saja! Kami akan mulai berlarian seperti ayam tanpa kepala di tahun 2036, sama seperti yang kami lakukan untuk Y2K. Beberapa dari kita akan menghasilkan banyak uang dari menjadi konsultan Y2k38, Leonard Nimoy akan mengeluarkan buku lucu lain tentang bagaimana kita semua harus bersembunyi di hutan ...
paxdiablo
1
... dan semuanya akan reda, publik bertanya-tanya apa yang terjadi. Saya bahkan mungkin keluar dari masa pensiun untuk menghasilkan uang untuk warisan anak-anak :-).
paxdiablo
2
BTW, kami hanya menemukan satu bug Y2K dan itu adalah halaman web yang mencantumkan tanggal sebagai 1 Januari 19100. Latihan untuk pembaca mengapa ...
paxdiablo
9
Jika acara yang terjadi dalam 30 tahun adalah "kadaluwarsa cadangan ini," maka Anda mungkin dalam kesulitan SEKARANG, bukan pada 2038. Tambahkan 30 tahun ke time_t 32-bit hari ini, dan Anda mendapatkan tanggal di masa lalu. Program Anda mencari acara untuk diproses, menemukan acara yang sudah lewat waktu (hingga 100 tahun!), Dan menjalankannya. Ups, tidak ada lagi cadangan.
Rob Kennedy
5
time_tadalah tipe long intpada mesin 64 bit, selain itu long long int.
Ini adalah tipe integer bertanda 32-bit pada sebagian besar platform lawas. Namun, itu menyebabkan kode Anda menderita bug tahun 2038 . Jadi perpustakaan C modern harus mendefinisikannya sebagai int 64-bit yang ditandatangani sebagai gantinya, yang aman untuk beberapa miliar tahun.
Biasanya Anda akan menemukan typedef khusus implementasi yang mendasari ini untuk gcc di direktori bitsatau asmheader. Bagi saya, ini/usr/include/x86_64-linux-gnu/bits/types.h .
Spesies C time_tmenjadi tipe nyata seperti double, long long, int64_t, int, dll.
Bahkan bisa unsignedsebagai nilai pengembalian dari banyak fungsi waktu menunjukkan kesalahan tidak -1, tetapi(time_t)(-1) - Pilihan implementasi ini tidak umum.
Intinya adalah bahwa "perlu tahu" jenisnya jarang. Kode harus ditulis untuk menghindari kebutuhan.
Namun "perlu tahu" yang umum terjadi ketika kode ingin mencetak mentah time_t. Casting ke tipe integer terluas akan mengakomodasi sebagian besar case modern.
time_t now =0;
time(&now);
printf("%jd",(intmax_t) now);// or
printf("%lld",(longlong) now);
Casting ke doubleatau long doubleakan bekerja juga, namun bisa memberikan output desimal yang tidak tepat
Saya perlu tahu situasi karena saya perlu mentransfer waktu dari sistem ARM ke sistem AMD64. time_t adalah 32 bit di lengan, dan 64 bit di server. jika saya menerjemahkan waktu ke dalam format, dan mengirim string, itu tidak efisien dan lambat. Oleh karena itu jauh lebih baik untuk mengirim seluruh time_t dan mengatasinya di server. Namun, saya perlu memahami jenisnya sedikit lebih karena saya tidak ingin nomornya hancur oleh perbedaan endianness antara sistem, jadi saya perlu menggunakan htonl ... tapi pertama-tama, berdasarkan kebutuhan untuk mengetahui, saya ingin untuk mengetahui tipe yang mendasarinya;)
Owl
Kasus "perlu tahu" lainnya, setidaknya untuk yang ditandatangani vs yang tidak ditandatangani adalah apakah Anda perlu berhati-hati saat mengurangi waktu. Jika Anda hanya "kurangi dan cetak hasilnya", maka Anda mungkin akan mendapatkan apa yang Anda harapkan pada sistem dengan time_t yang ditandatangani, tetapi tidak dengan time_t yang tidak ditandatangani.
Michael Firth
@MichaelFirth Case tersedia untuk integer ditandatangani time_t dan unsigned time_t di mana pengurangan mentah akan menghasilkan hasil yang tidak terduga. C menyediakan double difftime(time_t time1, time_t time0)pendekatan pengurangan yang seragam.
chux - Reinstate Monica
-3
time_thanya typedefuntuk 8 byte ( long long/__int64) yang dimengerti oleh semua kompiler dan OS. Kembali pada hari-hari, dulu hanya untuk long int(4 byte) tetapi tidak sekarang. Jika Anda melihat di time_tdalam crtdefs.hAnda akan menemukan kedua implementasi tetapi OS akan digunakan long long.
semua kompiler dan OS? Tidak. Pada sistem linux saya, kompiler mengambil implementasi yang ditandatangani 4 byte.
Vincent
Pada sistem Zynq 7010, time_t adalah 4bytes.
Burung hantu
1
Pada sistem tertanam saya bekerja pada time_t hampir selalu 32-bit atau 4 byte. Standar ini secara khusus menyatakan bahwa implementasi spesifik yang membuat jawaban ini salah.
long int
.Jawaban:
The time_t artikel Wikipedia Artikel memberi petunjuk pada ini. Intinya adalah bahwa jenis
time_t
tidak dijamin dalam spesifikasi C.sumber
time_t
dalam struktur data pada disk dapat terjadi. Namun, karena filesystem sering dibaca oleh sistem operasi lain, itu akan konyol untuk mendefinisikan filesystem berdasarkan pada jenis tergantung implementasi. Sebagai contoh, sistem file yang sama dapat digunakan pada sistem 32-bit dan 64-bit, dantime_t
mungkin berubah ukuran. Dengan demikian, filesystem perlu didefinisikan secara lebih tepat ("integer bertanda 32-bit yang memberikan jumlah detik sejak awal 1970, dalam UTC") daripada hanya sebagaitime_t
.time.h
konten. Artikel itu terhubung ke cppreference.com tetapi konten yang dikutip tidak ditemukan ...time_t
ditandatangani tidak benar. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… menyatakan bahwa berbagai hal harus berupa "tipe integer yang ditandatangani" atau "tipe integer yang tidak ditandatangani", tetapitime_t
hanya dikatakan bahwa itu "akan menjadi tipe integer" . Implementasi dapat membuattime_t
unsigned dan masih kompatibel dengan POSIX.[root]# cat time.c
[root]# gcc -E time.c | grep __time_t
typedef long int __time_t;
Ini didefinisikan
$INCDIR/bits/types.h
melalui:sumber
typedef __int32_t __time_t;
dantypedef __time_t time_t;
dalam aFreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386
. Hasil Anda secara eksplisit diatur seperti itu di Linux (setidaknya pada 2.6.32-5-xen-amd64 dari Debian).__time_t
dan tidaktime_t
menemukan jenis yang mendasarinyatime_t
? Menghilangkan langkah?typedef __time_t time_t;
, pemeriksaan kode di sekitarnya juga diperlukan untuk memastikan bahwa typedef sebenarnya digunakan dan bukan hanya bagian dari kompilasi bersyarat.typedef long time_t;
mungkin telah ditemukan juga.Standar
William Brendel mengutip Wikipedia, tetapi saya lebih suka dari mulut kuda.
C99 N1256 draft standar 7.23.1 / 3 "Komponen waktu" mengatakan:
dan 6.2.5 / 18 "Jenis" mengatakan:
POSIX 7 sys_types.h mengatakan:
mana
[CX]
yang didefinisikan sebagai :Ini adalah perpanjangan karena itu membuat jaminan yang lebih kuat: floating point keluar.
gcc one-liner
Tidak perlu membuat file seperti yang disebutkan oleh Quassnoi :
Pada Ubuntu 15.10 GCC 5.2 dua baris teratas adalah:
Command breakdown dengan beberapa kutipan dari
man gcc
:-E
: "Berhenti setelah tahap preprocessing; jangan jalankan compiler dengan benar."-xc
: Tentukan bahasa C, karena input berasal dari stdin yang tidak memiliki ekstensi file.-include file
: "Memproses file seolah" #include "file" "muncul sebagai baris pertama dari file sumber utama."-
: masukan dari stdinsumber
gcc -E -xc -include time.h /dev/null | grep time_t
Jawabannya jelas khusus untuk implementasi. Untuk mengetahui secara pasti untuk platform / kompiler Anda, cukup tambahkan output ini di suatu tempat dalam kode Anda:
Jika jawabannya adalah 4 (32 bit) dan data Anda dimaksudkan untuk melampaui 2038 , maka Anda memiliki 25 tahun untuk memigrasi kode Anda.
Data Anda akan baik-baik saja jika Anda menyimpan data Anda sebagai string, meskipun itu sesuatu yang sederhana seperti:
Kemudian baca saja kembali dengan cara yang sama (fread, fscanf, dll menjadi int), dan Anda memiliki waktu offset zaman Anda. Solusi serupa ada di. Net. Saya melewati nomor zaman 64-bit antara sistem Win dan Linux tanpa masalah (melalui saluran komunikasi). Itu memunculkan masalah pemesanan byte, tapi itu topik lain.
Untuk menjawab pertanyaan paxdiablo, saya akan mengatakan bahwa itu dicetak "19100" karena program ini ditulis dengan cara ini (dan saya akui saya melakukannya sendiri di tahun 80-an):
The
printf
pernyataan mencetak string tetap "Tahun ini: 19" diikuti dengan string nol-empuk dengan "tahun sejak tahun 1900" (definisitm->tm_year
). Pada tahun 2000, nilai itu adalah 100, jelas."%02d"
bantalan dengan dua nol tetapi tidak terpotong jika lebih dari dua digit.Cara yang benar adalah (ubah hanya ke baris terakhir):
Pertanyaan baru: Apa alasan pemikiran itu?
sumber
%zu
penentu format untuk memformatsize_t
nilai (seperti yang dihasilkan olehsizeof
), karena mereka tidak ditandatangani (u
) dan dengan panjang size_t (z
) ·printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
dan hindariz
masalah ini.Di bawah Visual Studio 2008, itu default ke
__int64
kecuali Anda mendefinisikan_USE_32BIT_TIME_T
. Anda lebih baik berpura-pura tidak tahu apa itu didefinisikan, karena itu dapat (dan akan) berubah dari platform ke platform.sumber
time_t
adalah tipelong int
pada mesin 64 bit, selain itulong long int
.Anda dapat memverifikasi ini di file header ini:
time.h
:/usr/include
types.h
dantypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Pernyataan di bawah ini tidak satu demi satu. Mereka dapat ditemukan di file header resp menggunakan pencarian Ctrl + f.)
1) Dalam
time.h
2) Dalam
types.h
3) Dalam
typesizes.h
4) Lagi di
types.h
sumber
long int
mana - mana. Lihat stackoverflow.com/questions/384502/…Ini adalah tipe integer bertanda 32-bit pada sebagian besar platform lawas. Namun, itu menyebabkan kode Anda menderita bug tahun 2038 . Jadi perpustakaan C modern harus mendefinisikannya sebagai int 64-bit yang ditandatangani sebagai gantinya, yang aman untuk beberapa miliar tahun.
sumber
Biasanya Anda akan menemukan typedef khusus implementasi yang mendasari ini untuk gcc di direktori
bits
atauasm
header. Bagi saya, ini/usr/include/x86_64-linux-gnu/bits/types.h
.Anda bisa saja grep, atau menggunakan doa preprocessor seperti yang disarankan oleh Quassnoi untuk melihat header tertentu.
sumber
Kode yang kuat tidak peduli apa jenisnya.
Spesies C
time_t
menjadi tipe nyata sepertidouble, long long, int64_t, int
, dll.Bahkan bisa
unsigned
sebagai nilai pengembalian dari banyak fungsi waktu menunjukkan kesalahan tidak-1
, tetapi(time_t)(-1)
- Pilihan implementasi ini tidak umum.Intinya adalah bahwa "perlu tahu" jenisnya jarang. Kode harus ditulis untuk menghindari kebutuhan.
Namun "perlu tahu" yang umum terjadi ketika kode ingin mencetak mentah
time_t
. Casting ke tipe integer terluas akan mengakomodasi sebagian besar case modern.Casting ke
double
ataulong double
akan bekerja juga, namun bisa memberikan output desimal yang tidak tepatsumber
double difftime(time_t time1, time_t time0)
pendekatan pengurangan yang seragam.time_t
hanyatypedef
untuk 8 byte (long long/__int64
) yang dimengerti oleh semua kompiler dan OS. Kembali pada hari-hari, dulu hanya untuklong int
(4 byte) tetapi tidak sekarang. Jika Anda melihat ditime_t
dalamcrtdefs.h
Anda akan menemukan kedua implementasi tetapi OS akan digunakanlong long
.sumber