【问题标题】:C++ get dates between two datesC++ 获取两个日期之间的日期
【发布时间】:2016-01-26 08:46:53
【问题描述】:

我把每个日期都放在一个 struct (vector<value>) 的向量中:

struct value {
    string code;
    string date;
    string name;
};

日期格式为“YYYY-MM-DD HH:MM:SS”

我想获取两个给定日期之间的日期(例如从 01/01/2016 到 01/02/2016)。我该怎么做?

【问题讨论】:

  • 好视频here代码here
  • 如果您使用“YYYY/MM/DD”格式,您将能够按date 字段的字母顺序排序(不解析它)并使用std::lower_bound 两次以获得所需的范围。
  • 这取决于您需要什么形式的结果,但我会使用 copy_if 和 lambda(函子 pre-11)。
  • 我注意到您对 SO 有点陌生,如果这里的答案之一解决了您的问题,请不要忘记接受该解决方案。

标签: c++ sorting date-range


【解决方案1】:

日期格式YYYY-MM-DD HH:MM:SS 的特殊之处在于字典(逐字母)比较与时间比较相同,因此您可以直接使用它。

如果您的容器最初未按日期排序,则您必须一一检查所有日期。 std::copy_if 提供了一种很好的方法:

std::vector<value> get_between(const std::vector<value>& v,
        const std::string& from, const std::string& to)
{
    std::vector<value> u;
    std::copy_if(v.begin(), v.end(), std::inserter(u, u.begin()),
    [from,to](const auto& val) {
        return val.date >= from && val.date <= to;
    });
    return u;
}

copy_if 遍历 [v.begin(), v.end()[ 并在 lambda 返回 true 时将元素从 u.begin() 向前插入 u。它们的顺序与您输入时的顺序相同。

如果您的范围已排序,则可以使用 std::lower_boundstd::upper_bound 来获取开始和结束迭代器:

std::vector<value> get_between(const std::vector<value>& v,
        const std::string& from, const std::string& to)
{
    value fromv { "", from, "" };
    auto begin = std::lower_bound(v.begin(), v.end(), fromv,
    [](const auto& lhs, const auto& rhs) {
        return lhs.date < rhs.date;
    });

    value tov { "", to, "" };
    auto end = std::upper_bound(begin, v.end(), tov,
    [](const auto& lhs, const auto& rhs) {
        return lhs.date < rhs.date;
    });

    return std::vector<value>(begin, end);
}

lower_boundupper_bound至少from的第一个值和大于to的第一个值,这样@的范围987654335@ 是值为[from, to] 的范围。

【讨论】:

  • 是的,范围是排序的。你能解释一下如何使用lower_bound和upper_bound吗?也许有代码:) 谢谢!
  • 这是一个非常聪明的解决方案,肯定会进入我的代码-sn-ps!
【解决方案2】:

这个问题是双重的:

  1. 如何从字符串表示中获取可排序的日期值
  2. 如何有效地对所述值进行排序。

从日期字符串中查找有效时间戳

C++ 使用 time_t 对象作为距设定日期(1970 年 1 月 1 日 UTC)There's plenty of concise information about that 的有效秒数,在每种情况下,您都可以将其视为以秒为单位的整数表示。

接下来,您需要知道如何将数据解析为时间戳:这里有一些相当有用的链接。

我的首选方法是mktime - 这是Here on stack-overflow 的一个示例。还有seems someone else has done the same course as you ;)

如果日期格式不寻常,您可能需要考虑使用A function of your own design。在这种情况下,使用scanf 通常是最简单的方法——这个函数的界面有点老派的“c 风格”,但这并没有改变它工作的简单事实,而且很好。 Here's a link to someone reading a simple-date with scanf.

原来我在下面写的代码接近The answer to this great question

#include <stdio.h>
#include <time.h>  
time_t GetDateFromObject(value & Date_Object)
{
    char * Date_String = Date_Object.date.c_str();
    int year, month, day, hour, minute, second;
    if(sscanf(Date_String , "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second) == 6)
    { 
        time_t rawTime;
        time(&rawTime);
        struct tm * parsedTime;
        parsedTime = localtime(&rawTime);

        // tm_year is years since 1900
        parsedTime->tm_year = year - 1900;
        // tm_months is months since january
        parsedTime->tm_mon = month - 1;
        parsedTime->tm_mday = day;
        parsedTime->tm_hour = hour;
        parsedTime->tm_min = minute;
        parsedTime->tm_sec = second;
        return mktime(parsedTime);
   }
}

日期的关联和排序

一旦您知道如何从日期中获取 time_t,您就可以开始创建数据的关联数组 - 在本例中,我将使用 map

下面是一个使用地图插入、排序和输出数据的示例。

#include<iostream>
#include<map>
#include<vector>
#include<ctime>

struct value {
    std::string code;
    std::string date;
    std::string name;
};

void Print_Range(std::vector<value> & Data, value & Date_Start, value & Date_end)
{
    std::map<time_t, value *> Associated_Data;
    for(auto Date_Object : Array_Of_Dates)
    {
        time_t Object_Time = GetDateFromObject(Date_Object);
        Associated_Data.insert(std::make_pair(Object_Time, & Date_Object); 
    }
    //as the std::map is sorted by-default, 
    //we can know locate the iterator for any two time codes
    time_t Search_From = GetDateFromObject(Date_Start);
    time_t Search_To = GetDateFromObject(Date_End);
    auto Start_IT = Associated_Data.find(Search_From);
    auto End_IT = Associated_Data.find(Search_To);

    std::cout << "Printing all dates in range \n";
    for(auto IT=Start_IT; IT != End_IT; IT++)
    {
        std::cout << IT->Second->date << '\n';
    }
}

注意事项:

  1. 我在这里使用 C++11 语法,如果您不了解 Range based loops,您可能需要阅读它们。
  2. 我假设您描述的结构存储在 vector 中。
  3. 我在这里使用的“GetDateFromObject”函数是用于获取时间戳的任何函数的占位符)
  4. Inserting data into a map using std::make_pair
  5. 我持有指向原始值对象的指针。

【讨论】:

  • 我的日期格式是“YYYY/MM/DD HH:MM:SS”,它简化了一些事情吗?
  • 非常好,您可以使用 scanf 来解决这个确切的问题 - 如果您使用格式更新您的问题,我会看到有关更新我的答案的信息;)
  • 稍作修改后 - 我认为应该这样做:)
【解决方案3】:

在示例中,您可以这样做:将所有日期转换为 time_t 值(日期和时间的数字表示),然后遍历您的向量并使用三个 time_t 数字之间的正常比较。供参考:man mktimeman strptime

【讨论】:

  • 我开始讨厌匿名的投票者会削弱帮助他人的积极性:(.
  • 我同意所说的反对票,你有我的赞成票,因为我试图提供帮助。也就是说,我想你的反对票来自 - 你没有提供任何代码(甚至转换日期值)你引用了 Man (请记住,大多数 Windows 用户不知道 man 是什么,也不喜欢在什么时候使用它他们这样做。)
猜你喜欢
  • 2018-01-11
  • 2018-09-17
  • 1970-01-01
  • 2010-10-05
  • 2017-06-03
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多