Tag Archive time

Byphunsanit

แก้เข้า linux / windows แล้วเวลาเปลี่ยน

ถ้าเครื่องลง dual boot หลังไปใช้ linux แล้วกลับมาบูทเข้า windows จะพบว่าเวลามันจะเปลี่ยนไปหลายชั่วโมง โดยที่ไม่ได้ตั้งเวลาใหม่แต่อย่างใด ทั้ง ๆ ที่ตอนใช้ลินุกซ์เวลาก็ถูกต้องนะ

ปัญหาแบบนี้สามารถแก้ได้ง่าย ๆ โดยพิมพ์ใน terminal ด้วยสิทธิ์ root

timedatectl set-local-rtc 1

จากนั้นปัญหานี้จะหมดไปละ

สาเหตุ ในคอมพิวเตอร์มีนาฬิกาอยู่ 2 ตัว คือ 1 นาฬิกาบนแมนบอร์ด ( bios / cmos / uefi ) 2 นาฬิกาบนระบบปฏิบัติการ โดยค่าตั้งต้น linux จะคิดว่านาฬิกาบนเมนบอร์จะเป็นเวลาตาม UTC ไม่ใช่เวลาท้องถิ่น แต่วินโดวน์จะคิดว่าเป็นเวลาท้องถิ่น เวลาที่เราใช้ linux หรือ windows ต่างก็ sync เวลาใหม่ลงไปที่นาฬิกาบนแมนบอร์ด แต่เพราะว่าทั้งสองตัวเข้าใจว่าเป็นจึงเห็นเวลาเปลี่ยนไป เปลี่ยนมา

ขอบคุณวิธีและคำอธิบายจาก Wrong Time Displayed in Windows-Linux Dual Boot Setup? Here’s How to Fix it

Byphunsanit

PHPExcel: จัดรูปแบบ format ข้อมูล

เมื่อวานเขียน export ข้อมูลออกเป็นไฟล์ excel โดยใช้เวลาไม่นาน เพราะโครงสร้างการทำงานมันเหมือนๆ งานที่เคยทำมา แต่มาตกม้าตายเอาที่การฟอร์เมตของแต่ละ column ให้ตรงกับชนิดข้อมูล เช่น type เป็น date ก็ควรให้เห็นเป็นวันที่ไม่ใช่เลข 1234155 อะไรก็ไม่ทราบ

<?php

include '../vendor/phpoffice/phpexcel/Classes/PHPExcel.php';

set_time_limit(0);

$objPHPExcel = new PHPExcel();

/* Set default style */
$defaultStyle = $objPHPExcel->getDefaultStyle();

$defaultStyle->getFont()
    ->setName('Arial')
    ->setSize(11);

$defaultStyle->getNumberFormat()
    ->setFormatCode('yyyy-mm-dd');

/* Set document properties */
$title = 'columnsType_' . date('Y-m-d_H:i');
$objPHPExcel->getProperties()->setCreator('CMS')
    ->setCategory('Exports Datas')
    ->setDescription($title)
    ->setKeywords('Exports Datas ' . date('Y-m-d'))
    ->setSubject($title)
    ->setTitle($title);

/* create new sheet */
$objWorkSheet = $objPHPExcel->getActiveSheet();
$objWorkSheet->setTitle('Exports Datas');

$columns = [
    'row_number' => ['title' => 'No.', 'type' => 'row_number'],

    'price' => ['title' => 'ราคา', 'type' => 'currency'],

    'dateEnd' => ['title' => 'เริ่มจำหน่าย', 'type' => 'date'],
    'dateStart' => ['title' => 'เริ่มจำหน่าย', 'type' => 'date'],

    'dateApproved' => ['title' => 'เวลาอนุมัติ', 'type' => 'datetime'],

    'height' => ['title' => 'สูง (เมตร)', 'type' => 'float'],
    'width' => ['title' => 'กว้าง (เมตร)', 'type' => 'float'],

    'calculate' => ['title' => 'สูตรคํานวณหวย', 'type' => 'formula'],

    'image' => ['title' => 'ภาพ', 'type' => 'image'],

    'items' => ['title' => 'จำนวน', 'type' => 'integer'],

    'productName' => ['title' => 'ชื่อสินค้า', 'type' => 'string'],

    'timeEnd' => ['title' => 'เวลาขาย', 'type' => 'time'],
    'timeStart' => ['title' => 'เวลาปิดการขาย', 'type' => 'time'],

    'url' => ['title' => 'page', 'type' => 'url'],
];

/* header */
$colNo = -1;
$rowNo = 1;
$colStrings = [];
foreach ($columns as $fieldId => $field) {
    $colNo++;
    $colStrings[$colNo] = $colString = PHPExcel_Cell::stringFromColumnIndex($colNo);
    $objWorkSheet->setCellValue($colString . '1', $field['title']);
    $objWorkSheet->setCellValue($colString . '2', 'type = ' . $field['type']);
}
$headerHeight = $rowNo = 2;

$objPHPExcel->getActiveSheet()->freezePane($colString . ($headerHeight + 1));

/* random data */
$datas = [];
for ($a = 0; $a < 10; $a++) {
    $temp = [];

    $temp['calculate'] = '=RAND()';
    $temp['dateApproved'] = date(DATE_ISO8601, mt_rand(0, 1499291999));
    $temp['dateEnd'] = date('Y-m-d', mt_rand(0, 1499291999));
    $temp['dateStart'] = date('Y-m-d', mt_rand(0, 1499291999));
    $temp['height'] = mt_rand(0, 10) / 10;
    $temp['image'] = 'http://lorempixel.com/400/200/sports/?st=' . mt_rand(1, 500);
    $temp['items'] = mt_rand(999, 9999999);
    $temp['price'] = mt_rand(100, 10000);
    $temp['productName'] = substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(10 / strlen($x)))), 1, 10);
    $temp['timeEnd'] = date('H:i:s', mt_rand(0, 1499291999));
    $temp['timeStart'] = date('H:i:s', mt_rand(0, 1499291999));
    $temp['url'] = 'https://plusmagi.com/?s=' . mt_rand(1, 500);
    $temp['width'] = mt_rand(0, 10) / 10;

    array_push($datas, $temp);
}

/* add data */
$row_number = 0;
foreach ($datas as $item) {
    $colNo = -1;
    $row_number++;
    $rowNo++;
    foreach ($columns as $fieldId => $field) {
        $colNo++;

        $coordinate = $colStrings[$colNo] . $rowNo;

        switch ($field['type']) {
            case 'date':
            case 'datetime':
            case 'time':{
                    $ts = strtotime($item[$fieldId]);
                    $value = PHPExcel_Shared_Date::PHPToExcel($ts);
                }break;

            case 'image':{
                    $value = $item[$fieldId];

                    $gdImage = imagecreatefromjpeg($value);
                    $objDrawing = new PHPExcel_Worksheet_MemoryDrawing(); /*create object for Worksheet drawing*/

                    $objDrawing->setCoordinates($coordinate); /*set image to cell*/
                    $objDrawing->setDescription('Customer Signature'); /*set description to image*/
                    $objDrawing->setHeight(50);
                    $objDrawing->setImageResource($gdImage);
                    $objDrawing->setName('Customer Signature'); /*set name to image*/
                    $objDrawing->setOffsetX(25); /*setOffsetX works properly*/
                    $objDrawing->setOffsetY(10); /*setOffsetY works properly*/
                    $objDrawing->setWidth(100); /*set width, height*/

                    $objDrawing->setWorksheet($objWorkSheet); /*save*/

                    $objWorkSheet->getRowDimension($rowNo)->setRowHeight(60); /* set row height*/
                }break;

            case 'row_number':{
                    $value = $row_number;
                }break;

            case 'url':{
                    $value = str_replace('http://', '', $item[$fieldId]);
                    $objWorkSheet->getCell($coordinate)
                        ->getHyperlink()
                        ->setTooltip('Click here to access page')
                        ->setUrl($item[$fieldId]);
                }break;

            default:{
                    $value = $item[$fieldId];
                }break;
        }

        $objWorkSheet->setCellValue($coordinate, $value);
    }
}

/* auto width column */
$cellIterator = $objWorkSheet->getRowIterator()->current()->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $cell) {
    $objWorkSheet->getColumnDimension($cell->getColumn())->setAutoSize(true);
}

/* format for columns */
$colNo = -1;
foreach ($columns as $fieldId => $field) {
    $colNo++;

    $coordinate = $colStrings[$colNo] . ($headerHeight + 1) . ':' . $colStrings[$colNo] . $rowNo;

    switch ($field['type']) {

        case 'currency':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode('#,##0.00');
                /*->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_NUMBER);*/
            }break;

        case 'date':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH);
            }break;

        case 'datetime':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME);
                /*->setFormatCode('Y-m-d H:i:s');*/
            }break;

        case 'float':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
            }break;

        case 'integer':
        case 'row_number':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode('#,##');
            }break;

        case 'time':{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4);
                /*->setFormatCode('Y-m-d H:i:s');*/
            }break;

        default:{
                $objWorkSheet->getStyle($coordinate)
                    ->getNumberFormat()
                    ->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
            }break;
    }

}

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $title . '.xlsx"');
header('Cache-Control: max-age=0');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
$objWriter->save('php://output');

หลักการต้องทำงานคู่กัน 2 ส่วนคือ

  1. ส่วนใส่ข้อมูล บางชนิดต้องแปลงข้อมูลก่อน เช่น date, datetime, timestamp และ time ต้องเปลี่ยนเป็น unix timestamp ก่อน
  2. ส่วนกำหนด cell format (ในตัวอย่างให้วิธีกำหนดทั้ง column ไปเลย) ต้องเลือกรูปแบบที่เหมาะสมโดยจะกำหนดเอง
    ->setFormatCode('Y-m-d H:i:s');

    หรือจะใช้ตามมาตราฐานก้ได้ Class PHPExcel_Style_NumberFormat ก็ได้

Byphunsanit

YII2: formatter

ถ้าทำระบบที่ออกแบบให้ลูกค้าจากต่างประเทศมาใช้งานได้อย่างสดวก อาจจะต้องเปลี่ยนการแสดงผลให้ตามความเคยชินของลูกค้า อย่างเช่น วันที่ คนไทยจะใช้ d/M/Y คือ วันที่/เดือน/ปี แต่คนอเมริกันจะใช้ M/d/Y คือ เดือนมาก่อน/วันที่/ปี แต่อัฟริการใต้และฐานข้อมูลส่วนใหญจะเก็บแบบ Y-M-d คือ ปี-เดือน-วัน จะสามารเรียงข้อมูลตามวันเวลา ได้ง่ายที่สุด แต่ไม่นิยมใช้กันในชีวิตประจำวัน ซึ่งถ้าไม่สังเกตุดีๆ อาจจะเข้าใจกันผิดได้

Yii2 ได้อำนวยความสดวกในส่วนนี้ให้โดยเพียงแค่ไปที่ไฟล์ \common\config\main.php เพิ่ม

    'components' => [
...
        'formatter' => [
            'currencyCode' => 'THB',
            'dateFormat' => 'd/M/Y',
            'datetimeFormat' => 'd/M/Y H:i:s',
            'defaultTimeZone' => 'Asia/Bangkok',
            'locale' => 'th-TH',
            'sizeFormatBase' => 1024,
            'timeFormat' => 'H:i:s',
        ],
...

ก็จะสามารถใช้ความสามารถนี้ได้

เริ่มจากวันและเวลากันก่อน

$date = date('c');
echo '<br>$date = '.$date,
'<br>',
'<br>dateFormat = '.Yii::$app->formatter->dateFormat,
'<br>asDate($date) = '.Yii::$app->formatter->asDate($date),
'<br>asDate($date, \'Y-M-d\') = '.Yii::$app->formatter->asDate($date, 'Y-M-d'),
'<br>',
'<br>datetimeFormat = '.Yii::$app->formatter->datetimeFormat,
'<br>asDatetime($date) = '.Yii::$app->formatter->asDatetime($date),
'<br>asTimestamp($date) = '.Yii::$app->formatter->asTimestamp($date);

ผลที่ได้คือ
$date = 2016-05-26T19:41:22+02:00

dateFormat = d/M/Y
asDate($date) = 26/5/2016
asDate($date, ‘Y-M-d’) = 2016-5-26

datetimeFormat = d/M/Y H:i:s
asDatetime($date) = 26/5/2016 19:41:22
asTimestamp($date) = 1464284482

เงินก็สามารถเปลี่ยนการแสดงผลได้เหมือนกัน

$value = 910097693;
echo '<br>$value = '.$value,
'<br>',
'<br>currencyCode = '.Yii::$app->formatter->currencyCode,
'<br>asCurrency($value) = '.Yii::$app->formatter->asCurrency($value),
'<br>asCurrency($value, \'USD\') = '.Yii::$app->formatter->asCurrency($value, 'USD');

ผลที่ได้คือ
$value = 910097693

currencyCode = THB
asCurrency($value) = THB 910,097,693.00
asCurrency($value, ‘USD’) = USD 910,097,693.00

ขนาดไฟล์ก็สามารถแปลงได้เหมือนกัน

$value = 910097693;
echo '<br>$value = '.$value,
'<br>',
'<br>sizeFormatBase = '.Yii::$app->formatter->sizeFormatBase,
'<br>asSize($value) = '.Yii::$app->formatter->asSize($value),
'<br>asShortSize($value) = '.Yii::$app->formatter->asShortSize($value),
'<br>asSize($value, 4) = '.Yii::$app->formatter->asSize($value, 4);

ผลที่ได้คือ
$value = 910097693

sizeFormatBase = 1024
asSize($value) = 867.94 mebibytes
asShortSize($value) = 867.94 MiB
asSize($value, 4) = 867.9368 mebibytes

อ่านเพิ่มเติม

Byphunsanit

เก็บ session ทำข้อสอบออนไลน์

ตัวอย่างระบบข้อสอบ online โดยนักเรียน นักศึกษา จะต้อง login ก่อนโดยจะเก็บข้อมูลส่วนตัว และลำดับคำถามไว้ในเซคชั่น

และเพราะว่า php ตั้งเวลาไว้ให้เซคชั่นมีอายุ 20 นาที แต่มีเวลาทำข้อสอบ 120 นาที ทำให้เซคชั่นหมดเวลาไปก่อน จึงต้องใช้ jQuery มาต่ออายุให้เซคชั่นทุกๆ 10 นาที เพื่อรักษาข้อมูลเอาไว้

ไฟล์แสดงข้อสอบ (ใช้จริงๆ ควรแยก javascript ไปไว้ในอีกที่หนึ่ง)

<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>ข้อสอบ</title>
      <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
   </head>
   <body>
<?php
if (empty($_POST))
{
?>
      <div class="container">
         <h2>Vertical (basic) form</h2>
         <div class="row">
            <div class="col-md-2"><b>Stat :</b></div>
            <div class="col-md-2" id="startA"></div>
            <div class="col-md-2"><b>End :</b></div>
            <div class="col-md-2" id="endA"></div>
            <div class="col-md-2"><b>Last Update :</b></div>
            <div class="col-md-2" id="periodsA"></div>
         </div>
         <form id="examinationF" action="examination.php" method="post">
            <div class="form-group">
               <label for="name">Name :</label>
               <input type="text" name="name" id="name" class="form-control" placeholder="Enter your name">
            </div>
            <div class="form-group">
               <label for="surname">Surname :</label>
               <input type="text" name="surname" id="surname" class="form-control" placeholder="Enter your surname">
            </div>
            <div class="checkbox">
               <label><input type="checkbox" name="accept">พร้อมทำข้อสอบในเวลาที่กำหนด</label>
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
         </form>
      </div>
      <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
      <script>
         $(function(){

            /* keep session */
            function sessionPostpone()
            {
               $.ajax({
                  "cache" : false,
                  "type" : "post",
                  "success" : function(datas)
                  {
                     $('#endA').text(datas.time_end);
                     $('#periodsA').text(datas.update+ '('+datas.periods+')');
                     $('#startA').text(datas.time_start);
                  },
                  "url" : "session.php"
               });
            }

            sessionPostpone();
            var interval = 1000 * 60 * 10; // every 10 minutes
            setInterval(function(){
               sessionPostpone();
            }, interval);

            /* submit form */
            var timeout = 1000 * 60 * 120; // 120 minutes
            setTimeout(function () {
               $('#examinationF').submit();
            }, timeout);

         })
      </script>
<?php
}
else
{
   echo'<h1>คำตอบของคุณคือ</h1>',
   '<pre>',print_r($_POST, true),'</pre>';
}
?>
   </body>
</html>

ไฟล์ไว้เรียกดูข้อมูล และยืดอายุ session ออกไป

<?php
session_start();

$time = new DateTime();

if(! isset($_SESSION['id']))
{
	$datas = [];
	$_SESSION['id'] = session_id();
	$_SESSION['time_start'] = $time->format('H:i:s');

	$time_end = $time->modify('+2 hour');
	$_SESSION['time_end'] = $time_end->format('H:i:s');
	$_SESSION['time_end_timestamp'] = time($time_end);
}

$period = 10;
$_SESSION['periods'] = round((strtotime($_SESSION['time_end']) - time($time)) / 60 / $period);
$_SESSION['update'] = $time->format('H:i:s');

header("Content-type: application/json; charset=utf-8");
echo json_encode($_SESSION);
Byphunsanit

HTML5 IE หน้าเว็บเพี้ยน

อ้ายอีที่ขัดขวางการเจริญเติมโตของเว็บเทคโนโลยีกันมานานคงไม่พ้น internet explorer ไออี ตัวปัญหาเจ้าเก่าเจ้าประจำ ดั้งเดิมนั้นเอง เพราะว่ามันโดนฝั่งมากับ windows และต่างจาก chrome, Firefox, opera ตรงที่เจ้าอื่นๆมันจะ update อัตโนมัติ พยามพัฒนาตัวเองให้เป็นคนใหม่ มีความสามารถมากขึ้นเสมอๆ แต่เจ้าที่ตัวนี้ user ต้องพยามในการอัพเดตมันเอง แถมวินโดวน์เก่าๆ ยังไม่สามารถลงเวอร์ชั่นที่ล่าสุดได้ตามข้อจำกัดของวินโดว์นั้นๆ

ถ้าเราใช่ HTML5 และ tag ใหม่ อย่าง article, aside, footer, header, nav, section, time หวังว่าท่าน google จะทรงโปรด เพราะว่าแบ่งข้อมูลให้ท่านพิจารณาในการทำ SEO อย่างเต็มที่ แต่กลับกลายเป็นว่าหน้าเว็บเละอย่างไม่เคยเป็นมาก่อนใน IE8 ลงไป ลองใช้ compatibility mode ไล่ version ต่ำลงมาเรื่อยๆ ถึงจะเห็นว่าเป็นที่ IE9 ลงมา

เป็นเพราะว่ามันเห็น tag ใหม่ๆ อย่าง article, aside, footer, header, nav, section, time เป็นการเขียนผิด โดนกะลาครอบอยู่กับ HTML4 สมัยเมื่อ 10 ปีที่แล้ว แถมพาลไม่สนใจ css ที่มี tag พวกนี้อยู่ด้วย วิธีแก้คือสร้าง object ใหม่อีกครั้งด้วย JavaScript

'article aside footer header nav section time'.replace(/\w+/g,function(n){document.createElement(n)})

หรือจะใช้ tools อย่าง html5shiv

<!--[if lt IE 9]>
    <script src="bower_components/html5shiv/dist/html5shiv.js"></script>
<![endif]-->

เราก็จะสามารถใช้ css กับเท็กใหม่ๆ พวกนี้ได้และควรใช้ css reset ไว้ด้วยครับ ช่วยได้เยอะเลย เกือบจะต้องเริ่มต้นเขียนกันใหม่