2010-10-05 3 views
5

Hãy xem xét phần nào của việc theo dõi this question. Về cơ bản, các cơ sở định dạng ngày/giờ C++ dường như bị phá vỡ vô vọng - rất nhiều để làm điều gì đó đơn giản như chuyển đổi chuỗi ngày/giờ thành một đối tượng, bạn thực sự phải sử dụng Boost.Datetime hoặc cũ C strftime/strptime cơ sở.C++: chuyển đổi chuỗi ngày/giờ thành tm struct

Vấn đề là không có giải pháp nào trong số này hoạt động trực tiếp với cài đặt ngôn ngữ C++ được nhúng vào đối tượng iostream cụ thể. Các cơ sở C sử dụng cài đặt miền địa phương C/POSIX toàn cầu, trong khi các thiết bị I/O trong Boost.Datetime dường như bỏ qua cài đặt miền địa phương iostream hoàn toàn bằng cách cho phép người dùng đặt trực tiếp tên tháng, ngày trong tuần, v.v.

Vì vậy, tôi muốn một cái gì đó mà sẽ tôn trọng các thiết lập miền địa phương thấm vào một dòng I/O cụ thể mà sẽ cho phép tôi chuyển đổi một chuỗi thành một struct tm. Nó có vẻ dễ dàng, nhưng tôi chạy vào chướng ngại vật xung quanh mọi ngóc ngách. Lúc đầu, tôi nhận thấy rằng một số triển khai của STL cung cấp một chức năng phi tiêu chuẩn std::time_get::get, vì vậy tôi quyết định thực hiện một cái gì đó tương tự. Về cơ bản, tôi sẽ lặp lại chuỗi định dạng và bất cứ khi nào tôi nhấn cờ định dạng, tôi sẽ sử dụng một trong các tiện ích time_get (như get_monthname, get_weekday, get_year, v.v.) để chuyển chuỗi đầu vào thành struct tm. Điều này có vẻ dễ dàng, ngoại trừ mỗi một trong các chức năng này đòi hỏi một phạm vi iterator chính xác. Bạn không thể chuyển đổi "Monday,", nó phải là "Monday" chính xác hoặc chuyển đổi không thành công. Vì các trình vòng lặp phải là istreambuf_iterator, bạn không thể đơn giản quét trước, vì mỗi lần tăng thay đổi vị trí nhận trong bộ đệm luồng. Vì vậy, về cơ bản bạn phải lần đầu tiên lặp qua luồng, sao chép từng ký tự vào một bộ lọc luồng khác và sau đó khi bạn nhấn dấu phân cách (như dấu cách hoặc dấu phẩy), hãy sử dụng bộ lọc luồng thứ hai với các tiện ích time_get. Đó là nghĩa đen như thể các nhà thiết kế C++ đã đi ra khỏi con đường của họ để làm cho điều này là khó chịu nhất có thể.

Vì vậy, có giải pháp dễ dàng hơn không? Hầu hết các lập trình viên C++ làm gì khi họ cần chuyển đổi chuỗi ngày/giờ thành một đối tượng? Chúng ta chỉ cần sử dụng các cơ sở C, và mất đi những lợi thế đi kèm với các cài đặt miền địa phương khác nhau thấm nhuần trên các đối tượng iostream khác nhau?

+0

Bạn đã nộp bất kỳ lỗi chống lại C++ thư viện? Khiếu nại như thế này thúc đẩy sự phát triển của họ. – Potatoswatter

+0

'std :: time_get :: get' được định nghĩa bởi C++ 0x 22.4.5.1.1/6… Tôi vừa tình cờ mở trang, nhưng tôi cũng giả sử nó trong C++ 03. – Potatoswatter

+0

Nó không có trong C++ 03: nó có sẵn trong một số triển khai nhưng nó không phải là tiêu chuẩn. –

Trả lời

2

Tăng sử dụng (các) ngôn ngữ chuẩn theo mặc định; bạn không cần phải bỏ qua bất cứ điều gì:

#include "boost/date_time/gregorian/gregorian.hpp" 
#include <iostream> 
#include <sstream> 
#include <ctime> 

int main(){ 
    using namespace boost::gregorian; 

    std::locale::global(std::locale("")); 
    std::locale german("German_Germany"); 
    std::locale french("French_France"); 

    date d1(day_clock::local_day()); 
    date d2; 
    std::stringstream ss("2002-May-01"); 

    std::cout << "Mine: " << d1 << " | "; 
    ss >> d2; 
    std::cout << d2 << '\n'; 

    std::cout.imbue(german); 
    std::cout << "Germany: " << d1 << " | "; 
    ss.imbue(german); 
    ss << "2002-Mai-01"; 
    ss >> d2; 
    std::cout << d2 << '\n'; 

    std::cout.imbue(french); 
    std::cout << "France: " << d1 << " | " << d2 << '\n'; 

    std::tm t = to_tm(d1); 
    std::cout << "tm: " << asctime(&t); 
} 

(Những tên miền địa phương là đặc trưng cho Windows, tất nhiên.) Output:

Mine: 2010-Oct-28 | 2002-May-01 
Germany: 2010-Okt-28 | 2002-Mai-01 
France: 2010-oct.-28 | 2002-mai-01 
tm: Thu Oct 28 00:00:00 2010 
0

Tại sao không sử dụng thư viện C? Nó gần như chắc chắn có sẵn trong thực hiện của bạn, và nó cũng được gỡ lỗi và thử nghiệm.

Nếu nó thiếu một số tính năng, chắc chắn sẽ dễ dàng hơn khi thực hiện chức năng trình bao bọc mà làm việc theo múi giờ bạn mong muốn.

+0

Nếu chương trình được thiết kế xung quanh ngôn ngữ C++, tôi cho rằng nó có thể bất tiện khi dịch ngược sang ngôn ngữ C ... mặc dù tôi không thấy nó có thể nhiều hơn nhận tên từ locale :: name() và chuyển đến setlocale ()/newlocale() ... có thể khá chậm. – Potatoswatter

+0

Nó phụ thuộc vào cách anh ta sử dụng chúng. Gọi 'std :: locale :: global()' cũng sẽ đặt ngôn ngữ C nếu đối tượng locale đã cho có tên. Nếu anh ta nhúng các luồng riêng lẻ với các miền khác nhau, anh ta sẽ phải đặt và đặt thủ công ngôn ngữ C mỗi khi anh ta sử dụng một trong số đó (hoặc ít nhất, mỗi lần anh ta sử dụng một lần để xử lý ngày). Thật dễ dàng để viết một lớp học trợ giúp để giúp đỡ với điều đó, mặc dù. –

0

Tôi luôn cố gắng sử dụng các chuỗi độc lập địa phương để tuần tự hóa dữ liệu. Làm cho cuộc sống dễ dàng hơn nhiều.