【问题标题】:Unify timestamps as date strings将时间戳统一为日期字符串
【发布时间】:2017-07-02 20:33:26
【问题描述】:

MATLAB R2015b

我有一个表格,每行的两列中包含一个日期字符串和一个时间字符串,格式各异:

11.01.2016 | 00:00:00 | data

10/19/16 | 05:29:00 | data

12.02.16 | 06:40 | data

我想将这两列转换为具有通用格式的一列:

31.12.2017 14:00:00

我当前的解决方案在每一行上使用循环并将列组合为字符串,检查各种格式以使用 datetime 和适当的格式字符串,然后使用 datestr 和所需的格式字符串。 Datetime 无法自动确定输入字符串的格式。

您可以想象,这对于大型表(大约 50000 行)来说非常慢。

有没有更快的解决方案?

提前致谢。

【问题讨论】:

    标签: matlab datetime matlab-table


    【解决方案1】:

    我尝试对代码进行矢量化。诀窍是

    1. 转换表格 > 单元格 > 字符数组,然后
    2. 处理 char 字符串,然后
    3. 从 char-array > cell > table 转换回来

    此外,还有一个重要的位是用向量化的方式用“null”字符填充所有长度较短的单元格。没有这个,就不可能从 cell > char-array 转换。这是代码。 clc 全部清除

    %% create Table T
    d={'11.01.2016';
       '10/19/16';
       '12.02.16'};
    
    t={'00:00:00';
      '05:29:00';
      '06:40'};
    dat=[123;
        456;
        789];
    
    T = table(d,t,dat);
    
    %% deal with dates in Table T
    % separate date column and convert to cell
    dd = table2cell(T(:,1));
    % equalize the lengths of all elements of cell
    % by padding 'null' in end of shorter dates
    nmax=max(cellfun(@numel,dd));
    func = @(x) [x,zeros(1,nmax-numel(x))];
    temp1 = cellfun(func,dd,'UniformOutput',false);
    % convert to array for vectorized manipulation of char strings
    ddd=cell2mat(temp1);
    % replace the separators in 3rd and 6th location with '.' (period)
    ddd(:,[3 6]) = repmat(['.' '.'], length(dd),1);
    % find indexes of shorter dates 
    short_year_idx = find(uint16(ddd(:,nmax)) == 0);
    % find the year value for those short_year cases
    yy = ddd(short_year_idx,[7 8]);
    % replace null chars with '20XX' string in desirted place
    ddd(short_year_idx,7:nmax) = ...
        [repmat('20',size(short_year_idx,1),1) yy];
    % convert char array back to cell and replace in table
    dddd = mat2cell(ddd,ones(1,size(d,1)),nmax);
    T(:,1) = table(dddd);
    
    %% deal with times in Table T
    % separate time column and convert to cell
    tt = table2cell(T(:,2));
    % equalize the lengths of all elements of cell
    % by padding 'null' in end of shorter times
    nmax=max(cellfun(@numel,tt));
    func = @(x) [x,zeros(1,nmax-numel(x))];
    temp1 = cellfun(func,tt,'UniformOutput',false);
    % convert to array for vectorized manipulation of char strings
    ttt=cell2mat(temp1);
    % find indexes of shorter times (assuming only ':00' in end is missing
    short_time_idx = find(uint16(ttt(:,nmax)) == 0);% dirty hack, as null=0 in ascii
    % replace null chars with ':00' string
    ttt(short_time_idx,[6 7 8]) = repmat(':00',size(short_time_idx,1),1);
    % convert char array back to cell and replace in table
    tttt = mat2cell(ttt,ones(1,size(t,1)),nmax);
    T(:,2) = table(tttt);
    

    【讨论】:

    • 但是我必须进行一些调整以使其适合 m 但是我必须进行一些调整以适应我的需要:查找美国日期格式并切换月份和日期 usDates = ddd(:,3) == '/'; ddd(usDates, [1 2 4 5]) = ddd(usDates, [4 5 1 2]);我不得不将 nmax 分别设置为 10 和 8。当仅存在两位数年份或仅存在非秒显示元素时,建议的计算失败。我删除了 find 调用,因为逻辑索引要快一点。将两个char数组合二为一:tttt = mat2cell(tttt,ones(1,size(raw,1)),nmaxTimes+nmaxDates+1);
    • 是的,可以定制。从您给出的示例中,我只是展示了如何将数据从表转换为数组结构(更容易矢量化)。
    【解决方案2】:

    如果您将两列元胞数组称为c1c2,那么应该可以这样:

    c = detestr(datenum(strcat(c1,{' '},c2)), 'dd.mm.yyyy HH:MM:SS')
    

    然后,您需要删除旧列并将此c 放在它们的位置。但是,在内部,datenum 必须做与您正在做的事情类似的事情,所以我不确定这是否会更快。我怀疑这是因为(我们可以希望)标准功能得到了优化。

    如果您的表格未将它们表示为元胞数组,那么您可能需要执行预处理步骤以形成strcat 的元胞数组。

    【讨论】:

    • 遗憾的是 datenum 无法区分不同的日期格式:-/
    • 您可能不需要在中间调用datenum - 在字符串上调用detestr 可能就足够了,但我怀疑这对于区分会更好。你有多少种日期格式?您的示例中的那些似乎足够可识别。在示例中,看起来传入的日期是“美式”,前一个月是前一天,而输出显然是前一天是“欧式”。这通常是真的吗?也许尝试转换所有输入“。”到 '/'?点格式在美国不是标准的,看起来它在 Matlab 中的默认支持可能较少。 @user2760995
    猜你喜欢
    • 1970-01-01
    • 2011-05-05
    • 2019-07-30
    • 2011-03-16
    • 2016-09-15
    • 1970-01-01
    • 2012-10-25
    • 2012-05-16
    • 2012-06-23
    相关资源
    最近更新 更多