DataTable DateTime字段排序异常求助(巴西格式DD/MM/YYYY)
解决DataTables服务端DateTime字段按字符串排序的问题
你遇到的核心问题很明确:服务端返回的是格式化后的巴西日期字符串(DD/MM/YYYY),当触发排序时,DataTables会基于这个字符串进行比较,而非原始的DateTime类型,自然会出现排序逻辑错误(比如01/10/2023会排在02/09/2023前面,因为字符串比较时"01" < "02")。
下面给你两种可行的解决方案,推荐第一种,更简洁且不需要大幅改动前端结构:
方法一:服务端排序用原始日期,前端显示格式化后的日期
这个方案只需要调整服务端代码,前端保持原样即可:
1. 修改server-side.php的SQL查询
保留原始的register日期字段,同时生成格式化后的巴西日期列:
// 替换原查询语句 $sql_query = "SELECT id, register as register_raw, date_format(register, '%d/%m/%Y') as register, name, level FROM customers";
2. 调整排序逻辑,指定用原始日期字段排序
当排序目标是日期列(索引1)时,强制使用原始的register_raw字段排序,而非格式化后的字符串:
// 替换原排序代码段 $sortColumn = $columns[$params['order'][0]['column']]; // 如果排序的是日期列,切换到原始日期字段 if ($sortColumn === 'register') { $sortColumn = 'register_raw'; } $sqlRec .= " ORDER BY ". $sortColumn ." ".$params['order'][0]['dir']." LIMIT ".$params['start']." ,".$params['length']." ";
3. 调整数据返回逻辑,只传需要的字段
改用关联数组获取数据,避免字段顺序混乱,只返回前端需要的内容:
// 替换原循环代码 while( $row = mysqli_fetch_assoc($queryRecords) ) { $data[] = array( $row['id'], $row['register'], $row['name'], $row['level'] ); }
方法二:前端用隐藏列存原始日期,配置排序规则
如果不想改动服务端查询结构,可以让服务端返回原始日期+格式化日期,前端用隐藏列存储原始日期,指定排序时使用隐藏列:
1. 修改server-side.php的查询和返回
返回原始日期和格式化后的日期:
$sql_query = "SELECT id, register, date_format(register, '%d/%m/%Y') as register_br, name, level FROM customers"; // 替换循环代码 while( $row = mysqli_fetch_assoc($queryRecords) ) { $data[] = array( $row['id'], $row['register'], // 原始日期(用于排序) $row['register_br'], // 巴西格式日期(用于显示) $row['name'], $row['level'] ); }
2. 修改前端index.php的DataTables配置
添加隐藏列存储原始日期,配置显示列使用隐藏列排序:
$(document).ready(function(e){ $('#server-side').dataTable({ "bProcessing": true, "serverSide": true, "aoColumnDefs": [ { "bSearchable": false, "bVisible": false, "aTargets": [0] }, { "bVisible": false, "aTargets": [1] }, // 隐藏原始日期列 { "aTargets": [2], "orderData": [1] }, // 显示列使用隐藏列排序 { "aTargets": [5], // OPTIONS列索引变为5 "mRender": function ( data, type, full ) { return '<a href="view.php?id=' + full[0] + '" class="btn btn-sm btn-success"><i class="fa fa-eye"></i> VIEW</a> '+ '<a href="edit.php?id=' + full[0] + '" class="btn btn-sm btn-success"><i class="fa fa-pencil"></i> EDIT</a> '+ '<a href="#" class="btn btn-sm btn-success" data-toggle="modal" data-target="#delete-modal" data-customer="' + full[0] + '"><i class="fa fa-trash"></i> DELETE</a>'; } } ], language: { processing: "processing...", }, "ajax":{ url :"server-side.php", type: "POST", error: function(){ $("#post_list_processing").css("display","none"); } }, "order": [ 2, "desc"], // 排序目标改为显示列的索引2 }); });
同时调整表头,添加隐藏列的占位:
<thead> <tr> <th>ID</th> <th>原始日期(隐藏)</th> <th>REGISTER</th> <th>NAME</th> <th>LEVEL</th> <th>OPTIONS</th> </tr> </thead>
额外提醒:修复SQL注入风险
你当前的代码直接将用户搜索参数拼接到SQL中,存在严重的SQL注入风险,建议改用预处理语句:
// 替换原搜索条件处理 if( !empty($params['search']['value']) ) { $searchValue = "%".$params['search']['value']."%"; $where_condition = " WHERE ( name LIKE ? OR register LIKE ? )"; } // 执行总记录查询 $stmt = mysqli_prepare($con, $sqlTot); if (!empty($params['search']['value'])) { mysqli_stmt_bind_param($stmt, "ss", $searchValue, $searchValue); } mysqli_stmt_execute($stmt); $queryTot = mysqli_stmt_get_result($stmt); $totalRecords = mysqli_num_rows($queryTot); // 执行分页查询同理 $stmtRec = mysqli_prepare($con, $sqlRec); if (!empty($params['search']['value'])) { mysqli_stmt_bind_param($stmtRec, "ss", $searchValue, $searchValue); } mysqli_stmt_execute($stmtRec); $queryRecords = mysqli_stmt_get_result($stmtRec);
内容的提问来源于stack exchange,提问作者Gregory
相关产品推荐
相关产品推荐

