Boost库学习の时间日期处理

记录一下Boost程序库的学习
系统:win11下WSL2,ubuntu子系统

安装Boost程序库

sudo apt-get install libboost-dev

安装好了以后就可以在/usr/include目录下看到boost目录了,切换进去可以看到,各种包含文件都是.hpp文件,意思是这些文件和我们常见到的头文件加静态库动态库文件不一样,我们经常可以看到声明放在头文件,实现放在库文件来对实现进行封装的形式,但Boost不一样,它把声明和实现放在同一个文件里,即.h+.cpp,只有少量库需要构建时指定链接。让我们测试一下

#include <iostream>
#include <boost/version.hpp>
#include <boost/config.hpp>

int main() {
    
    

        std::cout << BOOST_VERSION << std::endl;
        std::cout << BOOST_LIB_VERSION << std::endl;
        std::cout << BOOST_PLATFORM << std::endl;
        std::cout << BOOST_COMPILER << std::endl;
        std::cout << BOOST_STDLIB << std::endl;

        return 0;
}

编译运行一下

jack@DESKTOP-SJO8SMG:/mnt/c/Users/samu$ g++ -o version version.cpp -I .
jack@DESKTOP-SJO8SMG:/mnt/c/Users/samu$ ./version
107100
1_71
linux
GNU C++ version 9.3.0
GNU libstdc++ version 20200808

可以看到,我们下载的是1_71版本的boost版本,测试完成。

c语言中的时间与日期库

学习之前我对书本中所说的c语言得到时间日期进行了一下了解,主要是以下两个函数:time和loacltime函数

#include <time.h>
time_t time(time_t *timer);
struct tm *localtime(const time_t *timer);
//重要的变量
typedef long     time_t;    // 时间值time_t 为长整型的别名
struct tm {
    
    
   int tm_sec;         /* 秒,范围从 0 到 59        */
   int tm_min;         /* 分,范围从 0 到 59        */
   int tm_hour;        /* 小时,范围从 0 到 23        */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31    */
   int tm_mon;         /* 月,范围从 0 到 11        */
   int tm_year;        /* 自 1900 年起的年数        */
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6    */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365    */
   int tm_isdst;       /* 夏令时                */
};

基本的使用就围绕time.h中的这几个函数和变量来进行。然后是一个测试程序。

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

int main(void) {
    
    
        struct tm *t;
        time_t now;
        time(&now);
        t = localtime(&now);

        printf("%d.%d.%d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
        printf("一年中第%d天\n", t->tm_yday);
        printf("%d:%d:%d\n", t->tm_hour, t->tm_min, t->tm_sec);
        printf("date and time:%s", asctime(t));
        return 0;
}

注意,上面是c代码,而且在linux环境下,windows环境下的vs编译会有所不同,像微软的vs常常有个安全警告,结果输出如下:

jack@DESKTOP-SJO8SMG:/mnt/c/Users/samu$ ./outtime
2021.12.11
一年中第344天
20:32:57
date and time:Sat Dec 11 20:32:57 2021

以上就足以满足基本需求了,而反观c++,许多程序还是直接用着c的接口,然后作为准标准库之一的Boost中的timer、date_time和chrono就是用来处理处理时间和日期的。下面介绍的就是其中之一的timer。

Boost库のtimer

Boost1.48版以后,timer库就由两个组件组成,早期的timer和后面的cpu_timer,前者是基于标准c/c++库函数,后者则是基于chrono库的API,计时精度更高。而且更重要的是,Boost官方已经不再推荐使用前者,即前者的编译会出现警告,但由于我是初学者,所以就先学习早期的timer吧。

#include <boost/timer.hpp>

namespace boost {
    
    

class timer
{
    
    
 public:
         timer() {
    
     _start_time = std::clock(); } // postcondition: elapsed()==0
//         timer( const timer& src );      // post: elapsed()==src.elapsed()
//        ~timer(){}
//  timer& operator=( const timer& src );  // post: elapsed()==src.elapsed()
  void   restart() {
    
     _start_time = std::clock(); } // post: elapsed()==0
  double elapsed() const                  // return elapsed time in seconds
    {
    
     return  double(std::clock() - _start_time) / CLOCKS_PER_SEC; }

  double elapsed_max() const   // return estimated maximum value for elapsed()
  // Portability warning: elapsed_max() may return too high a value on systems
  // where std::clock_t overflows or resets at surprising values.
  {
    
    
    return (double((std::numeric_limits<std::clock_t>::max)())
       - double(_start_time)) / double(CLOCKS_PER_SEC); 
  }

  double elapsed_min() const            // return minimum value for elapsed()
   {
    
     return double(1)/double(CLOCKS_PER_SEC); }

 private:
  std::clock_t _start_time;
}; // timer

} // namespace boost

对于早期的timer,我们称为timer(v1),接下来都这么称呼,官方好像也这么称呼,它包含了timer和progress_timer两个小组件(两个class),前者就在/usr/include/boost/timer.hpp中,后者在/usr/include/boost/progress.hpp中,上面就是关于timer的实现,比较简单,一眼分明。

timer用来测量时间流逝,是个小型的计时器,提供毫秒级别的计时精度。让我们来看一下使用。

#include <iostream>
#include <boost/timer.hpp>

using namespace std;
using namespace boost;

int main() {
    
    
        timer now;

        cout << "最大时间间隔: "
                << now.elapsed_max() /3600 << "h" << endl;
        cout << "最小时间间隔:"
                << now.elapsed_min() << "s" << endl;
        cout << "时间过去了"
                << now.elapsed() << "s" << endl;

        now.restart();
        cout << "巴拉巴拉巴拉巴" << endl;
        cout <<"重启后现在时间过去了"
                << now.elapsed() << "s" << endl;

        return 0;
}
jack@DESKTOP-SJO8SMG:/mnt/c/Users/samu$ g++ timerp.cpp -o timerp
In file included from /usr/include/boost/config/header_deprecated.hpp:18,
                 from /usr/include/boost/timer.hpp:20,
                 from timerp.cpp:2:
/usr/include/boost/timer.hpp:21:1: note: #pragma message: This header is deprecated. Use the facilities in <boost/timer/timer.hpp> instead.
   21 | BOOST_HEADER_DEPRECATED( "the facilities in <boost/timer/timer.hpp>" )
      | ^~~~~~~~~~~~~~~~~~~~~~~
jack@DESKTOP-SJO8SMG:/mnt/c/Users/samu$ ./timerp
最大时间间隔: 2.56205e+09h
最小时间间隔:1e-06s
时间过去了0.000287s
巴拉巴拉巴拉巴
重启后现在时间过去了4e-06s     

因为timer小组件就这么几种方法,使用起来很简单,如果使用中的std::clock函数和std::clock_t变量也可以实现上面的功能(照搬即可,hhh)。如下:

#include <iostream>
#include <ctime>
#include <limits>

using namespace std;

int main() {
    
    

        clock_t t = clock();

        cout << "最大时间间隔: "
                << (double((numeric_limits<clock_t>::max) () ) - double(t)) / double(CLOCKS_PER_SEC) /3600 << "h" << endl;
        cout << "最小时间间隔:"
                << double(1) /double(CLOCKS_PER_SEC) << "s" << endl;
        cout << "时间过去了"
                << double(clock() - t) / CLOCKS_PER_SEC /3600 << "s" << endl;

        t = clock();
        cout << "巴拉巴拉巴拉巴" << endl;
        cout <<"重启后现在时间过去了"
                << double(clock() - t) / CLOCKS_PER_SEC << "s" << endl;

        return 0;
}

需要注意的是,上面编译的时候的确出现了来自Boost官方库的信息提示,就当做是警告了。

下面的是progress_timer的实现。

class progress_timer : public timer, private noncopyable
{
    
    
  
 public:
  explicit progress_timer( std::ostream & os = std::cout )
     // os is hint; implementation may ignore, particularly in embedded systems
     : timer(), noncopyable(), m_os(os) {
    
    }
  ~progress_timer()
  {
    
    
  //  A) Throwing an exception from a destructor is a Bad Thing.
  //  B) The progress_timer destructor does output which may throw.
  //  C) A progress_timer is usually not critical to the application.
  //  Therefore, wrap the I/O in a try block, catch and ignore all exceptions.
    try
    {
    
    
      // use istream instead of ios_base to workaround GNU problem (Greg Chicares)
      std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed,
                                                   std::istream::floatfield );
      std::streamsize old_prec = m_os.precision( 2 );
      m_os << elapsed() << " s\n" // "s" is System International d'Unites std
                        << std::endl;
      m_os.flags( old_flags );
      m_os.precision( old_prec );
    }

    catch (...) {
    
    } // eat any exceptions
  } // ~progress_timer

 private:
  std::ostream & m_os;
};

由上可得,progress_timer继承自timer和noncopyable(这个暂时不表),就是说,上面timer的使用progress_timer也能完全胜任,且progress_timer在析构的时候还能自动输出流逝时间,你需要的话,还能重定向输出到其他位置。以上就是timer(v1)的内容。

Boost库のdate_time

前面学习了timer(v1)定时器的使用,接下来学习下Boost库中的日期和时间库,首先是了解一下时间日期的度量定性。通常,根据地球的自转,前辈们确定了基本时间度量的依据,但后来人们发现,地球自转并不均匀,所以需要用闰秒闰月闰年来对时间进行调整。世界很大,因此诞生的时间度量体系也很多,其中我们的公历叫格里高利历,date_time库就是基于此,提供精确定义时间点、时间段和时间长度,加减若干天/月/年,支持与c中的tm结构体相互转换。

使用方式:在jamfile中指定lib生成date_time库,因为它是Boost中少数需要编译生成库文件才能使用的,但我上面使用的是ubuntu中直接下载的库,在我的/usr/lib中并没有出现libboost_date_time的库文件,所以我又另装了centos子系统在其下进行了boost库的编译安装。具体可参考我写的这个博客:centos7安装boost
确认了是可用的,所以可以供大家参考参考,上面搞定后,就能在你对应的lib目录下找到libboost_date_time.a的文件名,我这里是/usr/local/lib,仔细看看你编译过程的信息就能找到的。原本习惯了windows编程,准备通过#pragma comment来引入第三方库即可,没曾想这是windows特有的,所以只能通过输入编译命令时引入了。
另外关于date_time,它有两个组件,分别由两个头文件来管理:

//处理时间的组件
#include <boost/date_time/posix_time/posix_time.hpp>
//处理日期的组件
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::posix_time;
using namespace boost::gregorian;

之所以说是管理,是因为这两个头文件是对其他头文件的一个总包,是一个抽象概念,对于以后有新库组件的添加,直接在其内部引入头文件即可,其他程序引用的头文件依然还是这个。另外,编写程序时需要注意,这里处理时间可以看成数轴运算,存在时间点和时间段的概念,也就是它们之中存在运算。

如下是主要类date的一个构造,我们只看函数名就可以了,因为现在是准备使用其功能而不是实现其功能。

template<class T, class calendar, class duration_type_>
  class BOOST_SYMBOL_VISIBLE date : private
       boost::less_than_comparable<T, boost::equality_comparable<T> >
  {
    
    
  public:
    typedef T date_type;
    typedef calendar calendar_type;
    typedef typename calendar::date_traits_type traits_type;
    typedef duration_type_ duration_type;
    typedef typename calendar::year_type year_type;
    typedef typename calendar::month_type month_type;
    typedef typename calendar::day_type day_type;
    typedef typename calendar::ymd_type ymd_type;
    typedef typename calendar::date_rep_type date_rep_type;
    typedef typename calendar::date_int_type date_int_type;
    typedef typename calendar::day_of_week_type day_of_week_type;
    date(year_type y, month_type m, day_type d)
      : days_(calendar::day_number(ymd_type(y, m, d))){
    
    }
    date(const ymd_type& ymd)
      : days_(calendar::day_number(ymd)){
    
    }
    //let the compiler write copy, assignment, and destructor
    year_type        year() const
    month_type       month() const
    day_type         day() const
    day_of_week_type day_of_week() const
    ymd_type         year_month_day() const
    bool operator<(const date_type& rhs)  const
    bool operator==(const date_type& rhs) const
    //! check to see if date is a special value
    bool is_special()const
    //! check to see if date is not a value
    bool is_not_a_date()  const
    //! check to see if date is one of the infinity values
    bool is_infinity()  const
    //! check to see if date is greater than all possible dates
    bool is_pos_infinity()  const
    //! check to see if date is greater than all possible dates
    bool is_neg_infinity()  const
    //! return as a special value or a not_special if a normal date
    special_values as_special()  const
    duration_type operator-(const date_type& d) const

    date_type operator-(const duration_type& dd) const
    date_type operator-=(const duration_type& dd)
    date_rep_type day_count() const
    //allow internal access from operators
    date_type operator+(const duration_type& dd) const
    date_type operator+=(const duration_type& dd)

    //see reference
  protected:
    /*! This is a private constructor which allows for the creation of new
      dates.  It is not exposed to users since that would require class
      users to understand the inner workings of the date class.
    */
    explicit date(date_int_type days) : days_(days)
    explicit date(date_rep_type days) : days_(days.as_number())
    date_int_type days_;
  };

作为轻量级对象,它可被拷贝传值,date全面支持比较和流输入输出的操作,可当成int或者string类型。

#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>

using namespace std;
using namespace boost::gregorian;

int main() {
    
    

        //定义时间点
        date d1(2021, 12, 14);
        date d2(1997, Apr, 10);
        date d3 = from_string("2000-0-0");
        date d4 ( from_string("2004-8-11") );
        date d5 = from_undelimited_string("20160913");

        //输出当前日期
        cout << day_clock::local_day() << endl;
        cout << day_clock::universal_day() << endl;

        //输出时间点
        cout << d1 << endl;
        cout << "Today is the " << d1.day_of_week() << "th day in the week." << endl;
        cout << "This week is the " << d1.week_number() << "th week in this year." << endl;

        //输出特殊时间点
        cout << date(neg_infin) << endl;
        cout << date(pos_infin) << endl;
        cout << date(not_a_date_time) << endl;
        cout << date(max_date_time) << endl;
        cout << date(min_date_time) << endl;

        return 0;
}

如上进行date对象的构造和几个方法使用,然后编译运行一下,由于我的库文件放在/usr/local/lib中,且配置环境变量一直没成功,我干脆在编译时使用绝对路径。

[root@DESKTOP-SJO8SMG samu]# g++ timerp.cpp -o timerp /usr/local/lib/libboost_date_time.a
[root@DESKTOP-SJO8SMG samu]# ./timerp
terminate called after throwing an instance of 'boost::wrapexcept<boost::gregorian::bad_day_of_month>'
  what():  Day of month value is out of range 1..31
Aborted (core dumped)

不过可以看到,编译通过了,但运行却出错了,为何?因为上面使用not_a_date_time的枚举构造了一个无效日期,在输出时就会出现异常,因为这个日期的处理,date_time库是直接抛出异常,把这里的输出删掉即可。

[root@DESKTOP-SJO8SMG samu]# g++ timerp.cpp -o timerp /usr/local/lib/libboost_date_time.a#有资料说不需要-l参数,直接链接即可,加上反而出错
[root@DESKTOP-SJO8SMG samu]# ./timerp
2021-Dec-14
2021-Dec-14
2021-Dec-14
Today is the Tue day in the week.
This week is the 50th week in this year.
-infinity
+infinity
9999-Dec-31
1400-Jan-01

但在后续又发现几个错误,就是上面构建的d3对象,事实上是没有0月0日的,哈哈哈,over掉了。改正后的输出如上。另外要说明的是工厂类day_clock的静态方法local_day()和universal_day()的使用,它们会返回当天的日期,不过一个是本地日期一个是UTC日期,前者的使用依赖于操作系统的时区设置。上面说了not_a_date_time是表示无效日期的枚举,后面两个呢?max_date_time是指这个库允许输出的最大可能日期,min_date_time则是反过来,所以当你构造的日期对象超出界限也会报错。neg_infin和pos_infin枚举则是负无限日期和正无限日期的意思。

对于from_string()和from_undelimited_string()则是工厂函数,前者用斜杠或者连字符分隔年月日,后者不用分隔符。

        //输出date对象的年月日
        date::ymd_type ymd = d3.year_month_day();
        cout << d2.year() << "." << d2.month() << "." << d2.day() << endl;
        cout << ymd.year << "." << ymd.month << "." << ymd.day << endl;
        cout << to_iso_string(d2) << endl;
        cout << to_iso_extended_string(d3) << endl;

		//date对象的输入输出操作
        date d;
        cin >> d;
        cout << to_iso_extended_string(d) << endl;

输出年月日还可以使用year()、month()、day()函数,或者使用year_month_day()得到ymd_type结构,输出其year、month、day元素。

1997.Apr.10
2000.Feb.2
19970410
2000-02-02
2008-Jan-02#个人输入
2008-01-02

另外一个重要操作是支持与c结构体tm的相互转换,主要使用to_tm()函数和date_from_tm()函数。

		//tm和date的相互转换
        tm t = to_tm(d4);
        cout << t.tm_year << "." << t.tm_mon << "." << t.tm_mday << endl;
        d4 = date_from_tm(t);
        cout << to_iso_extended_string(d4) << endl;

由于date是对于许多c库的一层封装甚至更底层的封装,所以这里不需要再另行引入time.h头文件,因为内部已经进行过这一步了,我们直接用即可。结果输出如下:

104.7.11
2004-08-11

可以看到,我没有给tm结构体的年份加上1900,所以它输出的是从1900开始到现在的年份,另外它的月份是从0开始的,所以这里是7月份。

Boost时间长度计算のdays、months、years

Boost库中有着以天数为单位的时长对象date_duration,它支持比较操作和加减法还有递增递减操作,可以像操作整数那样操作它,但不支持乘法、除法、取余等运算,为了方便,date_time库把date_duration定义了一个typedef,就是day,我们可以定义如下对象:
days d1(3), d2(-3), d3(333);
类似days的还有months、years和weeks,需要知道的是,months和years全面支持加减乘除,成员函数number_of_months()和number_of_years()可返回月数和年数,而weeks是days的子类,单位是7,行为和days相同。

注:虽然是可以正常计算,但日期的计算还是要考虑我们的生活规律,比如d1为2004年2月29号,d1减一年得到的日期却是2003年2月28号,需要注意这种月末的计算。后面其实还有日期区间的概念,但目前还用不上,因为涉及区间就可以添加迭代器概念,date_time库存在日期迭代器的概念,而这个当我需要的时候再学习更新。

Boost库の时间处理

上面的是关于date_time库处理日期的介绍,接下来是关于其后的时分秒的时间处理的介绍。这个部件被boost::posix_time命名空间管理,上面有介绍了,主要使用的还是time_duration的度量类,这个类可以精确到微秒级(书上是这么说的),如果头文件前定义BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG,还可以进一步精确到纳秒级。以下是time_duration.hpp中关于time_duration的类构造:

 template<class T, typename rep_type>
  class BOOST_SYMBOL_VISIBLE time_duration : private
      boost::less_than_comparable<T, boost::equality_comparable<T> >
  /* dividable, addable, and subtractable operator templates
   * won't work with this class (MSVC++ 6.0). return type
   * from '+=' is different than expected return type
   * from '+'. multipliable probably wont work
   * either (haven't tried) */
  {
    
    
  public:
    // A tag for type categorization. Can be used to detect Boost.DateTime duration types in generic code.
    typedef void _is_boost_date_time_duration;
    typedef T duration_type;  //the subclass
    typedef rep_type traits_type;
    typedef typename rep_type::day_type  day_type;
    typedef typename rep_type::hour_type hour_type;
    typedef typename rep_type::min_type  min_type;
    typedef typename rep_type::sec_type  sec_type;
    typedef typename rep_type::fractional_seconds_type fractional_seconds_type;
    typedef typename rep_type::tick_type tick_type;
    typedef typename rep_type::impl_type impl_type;

    time_duration() : ticks_(0) {
    
    }
    time_duration(hour_type hours_in,
                  min_type minutes_in,
                  sec_type seconds_in=0,
                  fractional_seconds_type frac_sec_in = 0) :
      ticks_(rep_type::to_tick_count(hours_in,minutes_in,seconds_in,frac_sec_in))
    {
    
    }
    // copy constructor required for dividable<>
    //! Construct from another time_duration (Copy constructor)
    time_duration(const time_duration<T, rep_type>& other)
      : ticks_(other.ticks_)
    {
    
    }
    //! Construct from special_values
    time_duration(special_values sv) : ticks_(impl_type::from_special(sv))
    {
    
    }
    //! Returns smallest representable duration
    static duration_type unit()
    //! Return the number of ticks in a second
    static tick_type ticks_per_second()
    //! Provide the resolution of this duration type
    static time_resolutions resolution()
    //! Returns number of hours in the duration
    hour_type hours()   const
    //! Returns normalized number of minutes
    min_type minutes() const
    //! Returns normalized number of seconds (0..60)
    sec_type seconds() const
    //! Returns total number of seconds truncating any fractional seconds
    sec_type total_seconds() const
    //! Returns total number of milliseconds truncating any fractional seconds
    tick_type total_milliseconds() const
    //! Returns total number of nanoseconds truncating any sub millisecond values
    tick_type total_nanoseconds() const
    //! Returns total number of microseconds truncating any sub microsecond values
    tick_type total_microseconds() const
    //! Returns count of fractional seconds at given resolution
    fractional_seconds_type fractional_seconds() const
    //! Returns number of possible digits in fractional seconds
    static unsigned short num_fractional_digits()
    duration_type invert_sign() const
    bool is_negative() const
    bool operator<(const time_duration& rhs)  const
    bool operator==(const time_duration& rhs)  const
    //! unary- Allows for time_duration td = -td1
    duration_type operator-()const
    duration_type operator-(const duration_type& d) const
    duration_type operator+(const duration_type& d) const
    duration_type operator/(int divisor) const
    duration_type operator-=(const duration_type& d)
    duration_type operator+=(const duration_type& d)
    //! Division operations on a duration with an integer.
    duration_type operator/=(int divisor)
    //! Multiplication operations an a duration with an integer
    duration_type operator*(int rhs) const
    duration_type operator*=(int divisor)
    tick_type ticks() const
    //! Is ticks_ a special value?
    bool is_special()const
    //! Is duration pos-infinity
    bool is_pos_infinity()const
    //! Is duration neg-infinity
    bool is_neg_infinity()const
    //! Is duration not-a-date-time
    bool is_not_a_date_time()const
    //! Used for special_values output
    impl_type get_rep()const

  protected:
    explicit time_duration(impl_type in) : ticks_(in) {
    
    }
    impl_type ticks_;
  };

因为boost中组件所在的文件会直接由该组件名字命名,查找还是很方便的,但如果是边缘类就很难查找了。需要使用linux的查找命令,这个我还不太熟悉。time_duration有hours、minutes、seconds、millisec、microsec和nanosec,除了加减乘除四则运算,time_duration还支持比较和输入输出。
示例代码如下:

#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace std;
using namespace boost::posix_time;

int main() {
    
    

        //time_duration对象
        time_duration t1(12,12,12,12);
        time_duration t2(6, 66, 666, 6666);
        time_duration t_temp;
        cout << t1 << endl;
        cout << t2 << endl;

        //时分秒微妙
        hours h(8);
        minutes m(88);
        seconds s(888);
        millisec ms(8888);
        t2 = h + m + s + ms;
        cout << t2 << endl;
        cout << "has " << t2.total_seconds() << "secs." << endl;

        //time_duration的输入输出
        time_duration temp_t;
        cout << "请输入时间:" << endl;
        cin >> temp_t;
        cout << "输入的时间:" << endl << to_simple_string(temp_t) << endl << to_iso_string(temp_t) << endl;

        //转换成tm结构
        tm t = to_tm(temp_t);
        cout << t.tm_hour << ":" << t.tm_min << ":" << t.tm_sec << endl;

        return 0;
}

输出结果如下:

[root@DESKTOP-SJO8SMG samu]# ./timerp
12:12:12.000012
07:17:06.006666
09:42:56.888000
has 34976secs.
请输入时间:
23:33:33.10
输入的时间:
23:33:33.100000
233333.100000
23:33:33
[root@DESKTOP-SJO8SMG samu]# ./timerp
12:12:12.000012
07:17:06.006666
09:42:56.888000
has 34976secs.
请输入时间:
23:46:46
输入的时间:
23:46:46
234646
23:46:46

使用还是很简单的,这里不做赘述了,因为只是简单了解使用,并不打算详细学习,所以就先到这吧。

猜你喜欢

转载自blog.csdn.net/weixin_44948269/article/details/121878389
今日推荐