I'm coding an integration to a particular software that is not open-source and i have come across a column in the database called "TIME_" which is a 9-digit integer. This time represents Hours-Minutes-Seconds without years, months or days. There is a different column for that, which is called "DATE_". DATE_ columns format is this "2022-01-01 00:00:00". It does not hold hours, minutes, or seconds. Like i said TIME_ column is used for that and i've been trying solutions to get a certain time format from a 9-digit integer but i couldn't come up with anything that worked. By the way, on the UI you can see the converted format of the column "TIME_" but it doesn't say how it converts it and i don't have access to the source code. Here are the solutions i tried:
First I thought it was a time in milliseconds so i wrote a function that takes one parameter that is time in milliseconds and returns a formatted hours, minutes, and seconds but the output wasn't anywhere near what it said on the UI. "271399244" was the data in the column "TIME_" and my function returned "75:23:19" and on the UI it said "16:45:57".
Then i assumed it was an epoch and tried every epoch conversion function in php and they didn't return anywhere near the right format.
Then did some maths and took the value of TIME_ column from 2 data rows and calculated the difference then went to the UI and took the converted value of those 2 rows and also calculated the difference between those values. Then tried to find a correlation but it wasn't consistent at all. So i ran out of solutions.
Screenshots below for a more detailed description.
On the UI:
In the database rows in respective order:
EDIT: As i mentioned in the question, I do not have access to the source code. I don't know how the conversion is being made from 9-digit integer to hours-minutes-seconds as it is my goal to find out.
Date and time components will typically ask for the date format to be something like YYYy-MM-DD, so in the model, you cast that value to date then the input should start rendering the value on page load if that is the issue.
I could have a Note model
class Note extends Model
{
protected $fillable = [
'text',
'is_private',
'userable_type',
'userable_id',
'scope',
'created_date',
];
protected $casts = [
'is_private' => 'boolean',
'created_date' => 'date',
];
}
Using the date cast - https://laravel.com/docs/9.x/eloquent-mutators#attribute-casting
Then in the input, you can do something like
<DateComponent value="{{ $note->date }}" />
Sorry if I'm off base but thats what I understand the question to be.
If your having the same problem with the time format you can create a custom cast to convert the time from epoch and back if need
https://laravel.com/docs/9.x/eloquent-mutators#custom-casts
Could also be related to this issue, this link might help write a custom cast
How to convert a date YYYY-MM-DD to epoch in PHP
That might look something like this.
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class TimeCast implements CastsAttributes
{
/**
* Cast the given value.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param mixed $value
* #param array $attributes
* #return mixed
*/
public function get($model, $key, $value, $attributes)
{
// Could also use strtotime
return gmdate("H:i:s", $value / 1000);
}
* Prepare the given value for storage.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param array $value
* #param array $attributes
* #return mixed
*/
public function set($model, $key, $value, $attributes)
{
return strtotime($value) * 1000;
}
}
Related
Here is the original core file
https://github.com/phpbb/phpbb-core/blob/master/user.php
Looks the same as mine...
From symfony
/**
* Sets the Date header.
*
* #return $this
*
* #final since version 3.2
*/
public function setDate(\DateTime $date)
{
$date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
This was running fine and then all a sudden it crashed.
[16-Sep-2022 15:21:12 UTC] PHP Fatal error: Uncaught ArgumentCountError: DateTime::__construct() expects at most 2 parameters, 3 given in /home/groomlake/public_html/engine/user.php:629
I'm looking but I can't see what is causing it. Can someone point it out? Maybe I have been awake too long and I do not see it...
/**
* Format user date
*
* #param int $gmepoch unix timestamp
* #param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i.
* #param bool $forcedate force non-relative date format.
*
* #return mixed translated date
*/
function format_date($gmepoch, $format = false, $forcedate = false)
{
global $engine_dispatcher;
static $utc;
if (!isset($utc))
{
$utc = new \DateTimeZone('UTC');
}
$format_date_override = false;
$function_arguments = func_get_args();
/**
* Execute code and/or override format_date()
*
* To override the format_date() function generated value
* set $format_date_override to new return value
*
* #event core.user_format_date_override
* #var DateTimeZone utc Is DateTimeZone in UTC
* #var array function_arguments is array comprising a function's argument list
* #var string format_date_override Shall we return custom format (string) or not (false)
* #since 3.2.1-RC1
*/
$vars = array('utc', 'function_arguments', 'format_date_override');
extract($engine_dispatcher->trigger_event('core.user_format_date_override', compact($vars)));
if (!$format_date_override)
{
/*error is on the following line*/
$time = new $this->datetime($this, '#' . (int) $gmepoch, $utc);
$time->setTimezone($this->create_timezone());
return $time->format($format, $forcedate);
}
else
{
return $format_date_override;
}
}
You have a problem with your dynamic namespace system. More than likely you have changed the name of a dynamic global namespace.
Backtrack, go back, and restore your changes before you changed your dynamic namespace name. i.e. (engine)
I looked at phpBB and I can see your namespace is (engine) instead of the PhpBB original dynamic namespace name which was (phpbb). That is where your problem is stemming from.
You also may have changed your directory depth somewhere and the dynamic namespace function will cause the pages to not load.
phpBB is one of the very few that have a dynamic namespace system and it is a bit complicated for the average person to traverse in their mind.
I'm parsing Wikidata JSON datasets to collect historic data. So far I haven't found the right format to store them in PHP / MySQL (via Doctrine).
For the last few millennia, DateTime seems to work, but I don't want to limit my application to that. It might be totally possible that it will have to process the start time property of the Universe. Besides, I also want to store the precision of the data, since we might know the rough year of birth of one person and the exact minute for another one.
(Edit: For now, dates are enough, I can live without the time, my example was exaggerated. Still, I sometimes know the exact date, sometimes just the month or even the year.)
I've thought about creating my own class for dates (I'm not planning to calculate time differences or something like that), but I also don't want to re-invent the wheel.
Search results on a certain search engine as well as here are ... underwhelming, sadly.
Any ideas or experience that you can share?
For a kind of similar use-case, we ended up with storing values for each period of time, allowing to store everything in the db and query at various precision levels.
class YourAwesomeDateManager {
public
$millenium,
$century,
$decade,
$year,
$month;
// and so on...
function setDate() {
// Hydrate with the best precision available
}
public function getDate ($precision) {
// ...
}
}
This allows you to retrieve different date formats, and return 0 for unavailable precision fields
The thing is that there is no common name usage for periods above milleniums. So you'll have to be creative.
To suggest an answer to my own question: No, there seems to be nothing like this.
So I went on and implemented a function that does what I need. I abandoned my WikidataDate class draft since I'd just be instantiating dozens of these just to convert one string into another...
Thanks for your feedback, feel free to suggest improvements or different solutions!
const CALENDARMODEL = 'http://www.wikidata.org/entity/Q1985727';
const WIKIDATA_DATE_FORMAT = '/^[+]?(-?\d{1,11})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/';
const PRECISION_YEAR = 9;
const PRECISION_YEAR_AND_MONTH = 10;
const PRECISION_DATE = 11;
const PRECISIONS = [
self::PRECISION_YEAR,
self::PRECISION_YEAR_AND_MONTH,
self::PRECISION_DATE,
];
/**
* Parse a date object (a "value" node) coming from parsing Wikidata JSON.
*
* Example string outputs:
* - "2018-12-31" the last day of 2018
* - "333-11" the month of the battle of Issos
* - "-53" the year in which Lutetia (Paris) was first mentioned
* - "-13798000000" the beginning of the universe
*
* #param \stdClass $object
*
* #return string
*
* #throws \Exception
*/
private function parseWikidataDate(\stdClass $object): string
{
if (!WikidataEntityDenormalizer::validateObjectProperties($object, ['time', 'precision', 'calendarmodel'])) {
throw new \Exception('Object missing necessary properties');
}
if (!in_array($object->precision, static::PRECISIONS)) {
throw new \Exception('Unexpected precision: '.$object->precision);
}
if (static::CALENDARMODEL !== $object->calendarmodel) {
throw new \Exception('Unexpected calendar model');
}
$result = [];
preg_match(static::WIKIDATA_DATE_FORMAT, $object->time, $result);
if (7 !== count($result)) {
throw new \Exception(sprintf('Could not parse Wikidata date: %s', $object->time));
}
$date = $result[1];
if ('00' !== $result[2]) {
$date .= '-'.$result[2];
}
if ('00' !== $result[3]) {
$date .= '-'.$result[3];
}
return $date;
}
I'm using Laravel 5.1
I got a model:
class ExampleModel extends Model {
// ....
protected $dateFormat = 'Y.m.d';
protected $dates = ['first_date', 'second_date'];
// ...
}
So when I'm indexing ExampleModel elements, the date format is correct (ex 2015.07.31)
But on an edit form it uses the default format: 2015-07-31 00:00:00
I'm using Form::model() binding.
I know I could use getFirstDateAttribute() but it's not the solution I'm looking for. Because it's not elegant at all and once I defined the $dates array, it should work automatically in every case.
So is it a bug maybe? Or am I doing something wrong?
I solved my problem by overriding Carbon's default date format:
Carbon\Carbon::setToStringFormat('Y.m.d');
But Kelly's answer is much better and more elegant, I just post this one as well, maybe someone will find this useful once.
I've never done this before, but it seems to work on a basic example I put together. Note that I'm just calling the toArray method on the model in the form opening tag.
{!! Form::model($exampleModel->toArray(), ['route' => ['example-models.update', $exampleModel->id]]) !!}
{!! Form::label('first_date', 'First Date') !!}
{!! Form::text('first_date') !!}
{!! Form::close() !!}
The docs say that the dateFormat property determines the date format when the object is cast to json or an array.
I don't fully advise this as a fix because when you update the core you'll lose this fix, but maybe this should be posted as a pull request to Laravel's next version.
In \Illuminate\Database\Eloquent\Concerns\HasAttributes update the asDate function as follows. As you can see from the comments the asDate function still returns a timestamp even though it's 00:00:00.
/**
* Return a timestamp as DateTime object with time set to 00:00:00.
*
* #param mixed $value
* #return \Illuminate\Support\Carbon
*/
protected function asDate($value)
{
$date = $this->asDateTime($value)->startOfDay();
$date->setToStringFormat($this->getDateFormat());
return $date;
}
This allows you to control the format of a date from the model (note I'm differentiating between a date and datetime). Then use the casts variable to cast your variable to date format.
protected $casts = [
'start_date' => 'date',
'end_date' => 'date'
];
protected $dateFormat = 'Y-m-d';
The $dates variable cannot differentiate between a date and a datetime.
UPDATE
The real problem is the form model binding skips the helper function of the FormBuilder class. As you can see if you inspect \Collective\Html\FormBuilder::date
/**
* Create a date input field.
*
* #param string $name
* #param string $value
* #param array $options
*
* #return \Illuminate\Support\HtmlString
*/
public function date($name, $value = null, $options = [])
{
if ($value instanceof DateTime) {
$value = $value->format('Y-m-d');
}
return $this->input('date', $name, $value, $options);
}
It is correctly formatting date to 'Y-m-d' as specified in HTML5 spec. However at this point $value is actually null. So you have to update the generic input function.
/**
* Create a form input field.
*
* #param string $type
* #param string $name
* #param string $value
* #param array $options
*
* #return \Illuminate\Support\HtmlString
*/
public function input($type, $name, $value = null, $options = [])
{
...
//$value is null here
if (! in_array($type, $this->skipValueTypes)) {
//$value is fetched based on hierarchy set by
$value = $this->getValueAttribute($name, $value);
//necessary duplicate code to format date value
if ($type == 'date' && $value instanceof DateTime) {
$value = $value->format('Y-m-d');
}
}
...
}
UPDATE There is no need to update vendor code. Check out FormModelAccessors
https://laravelcollective.com/docs/5.2/html#form-model-binding
I have a field in database (Time) with this value 09:00:00.
I created the Entity and with Time Field
/**
* #var \DateTime
*
* #ORM\Column(name="m_01_ch", type="time")
*/
private $m_01_ch;
In my controller I retrieve the element and when I do:
$val = $myentity->getM01Ch();
My value is (in XDebug)
$val = {DateTime}[3]
date= "2015-07-08 09:00:00.000000"
timezone_type = 3
timezone "Europe/Rome"
If I get $val->date I have All the Date, but I want to get only 09:00:00
Can I take my "original" value without use Regex etc?
You can modify your entity where you are returning your value. In your function getM01Ch() do something like this
/**
* #return \DateTime
*/
public function getM01Ch()
{
$returnValue = $this->m_01_ch->format('h:i:s')
return $returnValue
}
Other than that I don't know if any better approach exists. More info
OOP noob here. I'd like to take advantage of CakePHP 2.3's short date methods in order to get "today" or "yesterday" when appropriate while changing the format of the date when the output is not "today" or "yesterday".
Example view: echo $this->Time->niceShort($user['User']['last_invited_on'];.
I've found the following in lib/Cake/Utility/CakeTime.php (Cake's TimeHelper uses the CakeTime utility.):
class CakeTime {
/**
* The format to use when formatting a time using `CakeTime::nice()`
*
* The format should use the locale strings as defined in the PHP docs under
* `strftime` (http://php.net/manual/en/function.strftime.php)
*
* #var string
* #see CakeTime::format()
*/
public static $niceFormat = '%a, %b %eS %Y, %H:%M';
/**
* The format to use when formatting a time using `CakeTime::timeAgoInWords()`
* and the difference is more than `CakeTime::$wordEnd`
*
* #var string
* #see CakeTime::timeAgoInWords()
*/
public static $wordFormat = 'j/n/y';
/**
* The format to use when formatting a time using `CakeTime::niceShort()`
* and the difference is between 3 and 7 days
*
* #var string
* #see CakeTime::niceShort()
*/
public static $niceShortFormat = '%B %d, %H:%M';
Can I somehow override this class's public properties in order to change the outputted date format whenever Time->niceShort is used in a view? (Is this "monkey patching"?) If so, what would be a good/clean way?
Or should I write a new class that extends CakeTime, and would this mean having to change $this->Time to $this->MyNewSpiffingCustomisedTime in views (which I'd rather not do as other people who are used to using Cake's Time are working on the project)? I wondered if this would be overkill just to change a property.
Old:
No need, you could just compare:
if (date('Y-m-d') != $date && date('Y-m-d', strtotime('-1 day')) != $date) {
//something
echo $this->Time->niceShort($date);
//something
}
Y-m-d is whatever your date format is i.e. Y-m-d H:i:s
New:
The proper way would be to call CakePHP wrapper for date('format', strtotime($date));. The CakePHP wrapper is defined as $this->Time->format('format', $date); and calls the previous php function I listed.
You shouldn't personalize base code if you plan to upgrade at any point. The only way (that I can think of right now) to still call $this->Time and extend the base code would be to implement a plugin called Time and include in your $helper and/or $component member variables Time.mySpiffyTimeThingo where mySpiffyTimeThingo is the name of the component or helper. These could extend/overwrite the current CakePHP CakeTime functions.
Why not extend the helper?
Create a class in app/View/Helper/myTimeHelper.php. In there add the reference to the old class you'll be extended like:
App::uses('TimeHelper', 'View/Helper');
class myTimeHelper extends TimeHelper {
public function niceShort(<whatever input the original is getting>) {
// your new logic for the things you want to change
// and/or a return TimeHelper::niceShort(<whatever>) for the cases that are
//fine as they are. If you don't need that then you can remove App::uses.
}
Finally you can have your helper imported as myTime with
public $helpers = array('myTime');
or even change the default Time to call myTime so you don't need to change anything else in your already written code:
public $helpers = array('Time' => array('className' => 'myTime'));