2014-01-31 3 views
2

У меня есть папка с файлами csv. Каждый файл csv назван по дате (например, 01JAN2013.csv, 02JAN2013.csv). Я должен прочитать файлы в порядке их даты (дата начала и дата окончания известны).Как перебирать диапазон дат в C++

Так что я пытаюсь пропустить даты, начиная с даты начала и до конца, чтобы генерировать имена файлов.

В настоящее время я делаю:

vector<string> dd{"01", "02", "03", "04", "05", "06", "07", "08", "09","10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20","21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"}; 
vector<string> mmm{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG","SEP", "OCT", "NOV", "DEC"}; 
vector<string> yyyy{"2011","2012","2013","2014"}; 

string filePath=DataFolderPath; 

for(int i=0;i<yyyy.size();i++) 
{ 
    for(int j=0;j<mmm.size();j++) 
    { 
     for(int k=0;k<dd.size();k++) 
     { 
      filePath.append(dd[k]); 
      filePath.append(mmm[j]); 
      filePath.append(yyyy[i]); 
      filePath.append(".csv"); 
     } 
    } 
} 

Определенно некрасиво, но он получает работу.

Есть ли более простой способ прокрутки дат в C++. Что-то вдоль линий:

for (currentDate = starDate; currentDate < endDate; currentDate++) { 

//Do stuff 

} 

UPDATE:

Это подход, который я, наконец, используется, сочетание обоих ответов ниже:

typdef struct tm Time; 
Time startDate=makeDate(3,1,2011); 
Time endDate=makeDate(24,1,2014); 
time_t end=mktime(&endDate); 

for(Time date=startDate;end>=mktime(&date);++date.tm_mday) 
{ 
    char buffer[16]; 
    strftime(buffer, sizeof(buffer), "%d%b%Y.csv", &date); 

    std::string filename(buffer); 
      //To convert month to CAPS 
    std::transform(filename.begin()+2, filename.begin()+5,filename.begin()+2, ::toupper); 


    std::cout << filename << "\n"; 
} 

Я также использовал makeDate вспомогательная функция, основанная на ответе адди, который возвращает struct tm вместо time_t:

Time makeDate(int day, int month, int year) 
{ 
Time ttm = {0}; 
ttm.tm_mday= day; 
ttm.tm_mon= month-1; 
ttm.tm_year= year-1900; 
return ttm; 
} 
+0

Похоже, что было бы легче найти файлы, которые есть, то просто сортировать их по дате, не так ли? –

+0

@JerryCoffin Каждый файл содержит только данные за определенную дату. Он не был создан/изменен в эту дату. SO сортировка файлов по дате не будет полезна. –

+0

Нет, я имею в виду сортировку по дате в названии. –

ответ

5

На самом деле это не может быть проще ... Но вы можете использовать функции времени от <ctime>. Что-то вроде этого:

string MakeFileName(time_t t) 
{ 
    static const char* months[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", 
            "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; 
    struct tm *ptm = localtime(&t); 

    char buffer[20]; 
    snprintf(buffer, 20, "%02d%s%04d.CSV", 
       ptm->tm_day, months[ptm->tm_month], ptm->tm_year+1900); 

    return string(buffer); 
} 

Теперь просто получить начальную и конечную даты корректные в значении time_t (помните, это в секундах). Вы можете просто использовать 00:00:00 на время.

// Note that day and month are 1-based. 
time_t GetDate(int day, int month, int year) 
{ 
    struct tm ttm = {0}; 
    ttm.tm_day = day; 
    ttm.tm_month = month-1; 
    ttm.tm_year = year-1900; 
    return mktime(&ttm); 
} 

С этим помощником вы можете установить даты начала и окончание легко:

time_t start = GetDate(1, 1, 2011); 
time_t end = GetDate(28, 10, 2013); 
for(time_t t = start; t <= end; t += 86400) 
{ 
    string filename = MakeFileName(t); 

    // TODO... 
} 
2

Если вы решили произвести имена, я думаю, что @paddy имеет право общей идеи, но реализация может быть открыта для небольшого улучшения. В частности, mktime не только конвертирует, но и может ... исправить свой ввод, поэтому, если вы дадите ему ввод 30 февраля, он знает, что это 1 или 2 марта, и изменит его соответствующим образом. Аналогично, он знает, что 32 December 2011 действительно 1 Jan 2012 и (снова) соответствующим образом регулирует вход.

Угадайте, вы также, вероятно, не хотите генерировать даты в будущем, и просто дали ему даты создания в конце года, потому что вы не хотели изменять его каждую дату. Я предполагаю, что генерация дат с даты, в которую она запускается, вероятно, достаточна.

С теми, в виду, я бы написать код больше, как это:

#include <time.h> 
#include <iostream> 

int main() { 
    struct tm date; 

    date.tm_mon = 1; 
    date.tm_mday = 1; 
    date.tm_year = 2011 - 1900; 

    time_t end = time(NULL); 

    for (; mktime(&date) < end; ++date.tm_mday) { 
     char buffer[16]; 

     strftime(buffer, sizeof(buffer), "%d%b%Y", &date); 
     std::cout << buffer << "\t"; 
    } 
} 

На данный момент это только печатает строки, но с ними генерируются правильно, используя их в качестве имен файлов обычно будет довольно тривиально.

Если вы хотите сделать так, как я предложил в комментарии, и получить все имена файлов, а затем отсортировать их по порядку по дате, вы можете конвертировать каждое имя файла в time_t, сортировку time_t. Один довольно простой способ сделать это с std::get_time манипулятором:

time_t cvt(std::string const &filename) { 
    std::istringstream in(filename); 
    struct tm date; 

    in >> std::get_time(&date, "%d%b%Y"); 
    return mktime(date); 
} 

С этим, вы можете (за одну возможность) поставить time_t с и имена файлов в std::map, то просто пройти через карту от начала до и обрабатывать каждый файл по порядку.

std::map<time_t, std::string> files; 
std::string file_name; 

while (get_file_name(&file_name)) 
    files[cvt(file_name)] = file_name; 

for (auto const &f : files) 
    process(f.second); 
+0

Почему размер буфера 16? Когда есть только 9 символов? –

+0

@ShayanRC: Я довольно регулярно кручу большинство размеров до двух. –

1
#include <boost/date_time.hpp> 

using namespace boost::gregorian; 

long dateDifference(string start_date, string end_date) 
{ 
    date _start_date(from_simple_string(start_date)); 
    date _end_date(from_simple_string(end_date)); 

    for(day_iterator iter = _start_date; iter!=_end_date; ++iter) 
    { 
     // Do what you want 
    } 
} 
Смежные вопросы